Beauty iFrame (version 1.9.3)

What is Beauty iFrame?

Beauty iFrame is an in-browser real-time augmented reality make-up web-app. The web-app allows for a fast, realistic live try-on experience on mobile or desktop directly from a brand’s web page.

Try Me!


Browser Support

Holition Beauty’s virtual makeup engine (FaceSDK) depends on many modern Web-APIs which are not implemented by all browsers. The AR experience also depends on access to the device camera to operate.

Minimum Specification

The following are the minimum specifications required to operate:

Camera Access

The user must grant the web-app access to their camera to allow the experience to operate. A pop-up provided by the browser will be presented to the user upon initialisation.


Installing

To install the experience onto an existing web-page simply cut and paste the following HTML snippet into your page:

<iframe frameBorder="0" style="width: 100%;height: 100%;" allow="camera" src="https://<DEPLOYMENT-URL>?cms-client-id=<CMS-CLIENT-ID>&license=<LICENSE>"</iframe>

The HTML code inserts a configurable iFrame element into the page. In effect placing a virtual makeup experience into a resizable window onto your site.


Getting Started

There are two parts to setting up your virtual make-up experience. First the look and feel of the experience. Second the make up products and looks available to the users within.

Configuring the Experience

To control the look and feel of the virtual experience either:

  1. Add parameters to the iFrame element src URL to enable features or launch with specific looks or products set
  2. Use the Holition Beauty CMS to configure button icons, copy and enabled features

[NB. URL parameters take priority over CMS settings]

iFrame Configuration

The iFrame element allows for direct control over certain features and launch configurations of the web-app. These configurations are performed via URL parameters provided to the iFrame src attribute as follows:

<iframe frameBorder="0" style="width: 100%;height: 100%;" allow="camera" src="https://<DEPLOYMENT-URL>?cms-client-id=<CMS-CLIENT-ID>&configuration-id=<CONFIG-ID>&license=<LICENSE>&locale=<LOCALE>&identifier-type=<TYPE>&identifier-value=<VALUE>&range-id=<RANGE-ID>&looks=<BOOLEAN>&features=<OPTION>&carousel=<BOOLEAN>&filter=<BOOLEAN>&product-info=<BOOLEAN>&look-info=<BOOLEAN>&add-basket=<BOOLEAN>&watermark=<BOOLEAN>&vtoggle=<BOOLEAN>&info-button=<BOOLEAN>&static-start=<BOOLEAN>&simplify-carousel-info=<BOOLEAN>&range-name=<RANGE-NAME>"</iframe>
Parameters
"aa" | "ab" | "ae" | "af" | "af-za" | "ak" | "am" | "am-et" | "an" | "ar" | "ar-ae" | "ar-bh" | "ar-dz" | "ar-eg" | "ar-iq" | "ar-jo" | "ar-kw" | "ar-lb" | "ar-ly" | "ar-ma" | "ar-om" | "ar-qa" | "ar-sa" | "ar-sy" | "ar-tn" | "ar-ye" | "as" | "av" | "ay" | "az" | "az-cyrl-az" | "az-latn-az" | "ba" | "be" | "be-by" | "bg" | "bg-bg" | "bh" | "bi" | "bm" | "bn" | "bn-in" | "bo" | "br" | "br-fr" | "bs" | "bs-cyrl-ba" | "bs-latn-ba" | "ca" | "ca-es" | "ce" | "ch" | "co" | "cr" | "cs" | "cs-cz" | "cu" | "cv" | "cy" | "da" | "da-dk" | "de" | "de-at" | "de-ch" | "de-de" | "div-mv" | "dv" | "dz" | "ee" | "el" | "el-gr" | "en" | "en-au" | "en-bz" | "en-ca" | "en-gb" | "en-ie" | "en-jm" | "en-nz" | "en-ph" | "en-tt" | "en-us" | "en-za" | "en-zw" | "eo" | "es" | "es-ar" | "es-bo" | "es-cl" | "es-co" | "es-cr" | "es-do" | "es-ec" | "es-es" | "es-gt" | "es-hn" | "es-mx" | "es-ni" | "es-pa" | "es-pe" | "es-pr" | "es-py" | "es-sv" | "es-uy" | "es-ve" | "et" | "et-ee" | "eu" | "eu-es" | "fa" | "fa-ir" | "ff" | "fi" | "fi-fi" | "fj" | "fo" | "fo-fo" | "fr" | "fr-be" | "fr-ca" | "fr-ch" | "fr-fr" | "fr-lu" | "fr-mc" | "fy" | "ga" | "gd" | "gl" | "gl-es" | "gn" | "gu" | "gu-in" | "gv" | "ha" | "he" | "he-il" | "hi" | "hi-in" | "ho" | "hr" | "hr-hr" | "ht" | "hu" | "hu-hu" | "hy" | "hy-am" | "hz" | "ia" | "id" | "id-id" | "ie" | "ig" | "ii" | "ik" | "io" | "is" | "is-is" | "it" | "it-ch" | "it-it" | "iu" | "ja" | "ja-jp" | "jv" | "ka" | "ka-ge" | "kg" | "ki" | "kj" | "kk" | "kk-kz" | "kl" | "km" | "km-kh" | "kn" | "kn-in" | "ko" | "ko-kr" | "kok-in" | "kr" | "ks" | "ku" | "kv" | "kw" | "ky" | "ky-kz" | "la" | "lb" | "lg" | "li" | "ln" | "lo" | "lo-la" | "lt" | "lt-lt" | "lu" | "lv" | "lv-lv" | "mg" | "mh" | "mi" | "mi-nz" | "mk" | "mk-mk" | "ml" | "mn" | "mn-mn" | "mr" | "mr-in" | "ms" | "ms-bn" | "ms-my" | "mt" | "my" | "na" | "nb" | "nb-no" | "nd" | "ne" | "ng" | "nl" | "nl-be" | "nl-nl" | "nn" | "nn-no" | "no" | "nr" | "nv" | "ny" | "ny-mw" | "oc" | "oj" | "om" | "or" | "os" | "pa" | "pa-in" | "pi" | "pl" | "pl-pl" | "ps" | "pt" | "pt-br" | "pt-pt" | "qu" | "rm" | "rn" | "ro" | "ro-ro" | "ru" | "ru-ru" | "rw" | "sa" | "sa-in" | "sc" | "sd" | "se" | "sg" | "si" | "sk" | "sk-sk" | "sl" | "sl-sl" | "sm" | "sn" | "so" | "sq" | "sq-al" | "sr" | "sr-cyrl-rs" | "sr-latn-rs" | "ss" | "st" | "su" | "sv" | "sv-fi" | "sv-se" | "sw" | "sw-tz" | "syr-sy" | "ta" | "ta-in" | "te" | "te-in" | "tg" | "th" | "th-th" | "ti" | "tk" | "tl" | "tn" | "to" | "tr" | "tr-tr" | "ts" | "tt" | "tt-ru" | "tw" | "ty" | "ug" | "uk" | "uk-ua" | "ur" | "ur-pk" | "uz" | "uz-cyrl-uz" | "uz-latn-uz" | "ve" | "vi" | "vi-vn" | "vo" | "wa" | "wo" | "xh" | "yi" | "yo" | "za" | "zh" | "zh-chs" | "zh-cht" | "zh-cn" | "zh-hk" | "zh-mo" | "zh-sg" | "zh-tw" | "zu" | "zu-za"

CMS Configuration

To use the CMS configuration the configuration-id iFrame parameter, described above, must be supplied with a valid config ID (found from the CMS administration control panel)

[NB. URL parameters take priority over CMS settings. To access the CMS please goto the portal cms. Info can be found in the Portal Guide]


API

The web-app allows for both dynamic control (actions) and real-time event reporting (events) to and from the parent host page.

Events

To listen to all internal events from the iframe just add the following script to your page, which will subscribe to events from the iFrame:

// Add window event listener functions
if (window.addEventListener) {
  window.addEventListener('load', handleForm, false);
  window.addEventListener('message', handleMessage, false);
}

// Subscribe to events when iFrame has loaded
function handleForm() {
  // Subscribe to events
  var win = document.getElementById('facesdk').contentWindow;
  win.postMessage(
    'subscribe',
    'https://holition-beauty-projects.holitionbeauty.com'
  );
}

// Handle events messages
function handleMessage(e) {
  if (e.origin !== 'https://holition-beauty-projects.holitionbeauty.com') {
    return;
  }

  const event = e.data;
  // [Respond to event messages here]
  console.log(
    `FaceSDK Event: component[${event.component}] type[${event.type}] data:`,
    event.data
  );
}

Upon subscription an event will be returned with the current SDK version number as follows:

interface Event {
  version: string;
}

Event responses are JSON formated as follows:

interface Event {
  component:
    | 'face_scan'
    | 'slider'
    | 'photo'
    | 'products'
    | 'sdk'
    | 'static_image';
  type:
    | 'scan_progress'
    | 'scan_results'
    | 'scan_button_click'
    | 'slider_button_click'
    | 'slider_thumb_drag'
    | 'close_photo_button_click'
    | 'photo_button_click'
    | 'photo_captured'
    | 'select_product'
    | 'select_look'
    | 'select_range'
    | 'select_filter'
    | 'initialised'
    | 'face_tracked'
    | 'camera_access'
    | 'feed_error'
    | 'error'
    | 'critical_error'
    | 'add_basket'
    | 'info_view'
    | 'info_close'
    | 'info_button'
    | 'image_select'
    | 'live_launch'
    | 'image_align_click'
    | 'finish_image_align'
    | 'static_launch'
    | 'filtered_products'
    | 'data_loaded';
  data: any | null;
}

Face-Scan

All face-scan related events have event_component set to face_scan.

Getting Results

The result of the face scan

interface Event {
  component: 'face_scan';
  type: 'scan_results';
  data: {
    results: {
      eyeColor: 'black' | 'blue' | 'brown' | 'green' | 'grey';
      eyeColorProbabilities: {
        black: number;
        blue: number;
        brown: number;
        green: number;
        grey: number;
      };
      eyeColorProbability: number;
      eyeShape: 'almond' | 'downturned' | 'rounded' | 'upturned';
      eyeShapeProbabilities: {
        almond: number;
        downturned: number;
        rounded: number;
        upturned: number;
      };
      eyebrowShape: 'high_arch' | 'straight' | 'thick';
      eyebrowShapeProbabilities: {
        high_arch: number;
        straight: number;
        thick: number;
      };
      faceShape: 'heart' | 'oval' | 'rounded' | 'square';
      faceShapeProbabilities: {
        heart: number;
        oval: number;
        rounded: number;
        square: number;
      };
      lipCoverage: 'full' | 'medium' | 'thin';
      lipCoverageProbabilities: {
        full: number;
        medium: number;
        thin: number;
      };
      mediaInputQuality: string;
      percentage: number;
      skinTone: 'dark' | 'deep' | 'light' | 'light_medium' | 'medium';
      skinToneProbabilities: {
        dark: number;
        deep: number;
        light_medium: number;
        light: number;
        medium: number;
      };
      skinToneProbability: number;
    };
  };
}
Seeing Progress

The progress of the face-scan

interface Event {
  component: 'face_scan';
  type: 'scan_progress';
  data: {
    progress: number;
  };
}
Notified When Starting

User has started the face scan experience

interface Event {
  component: 'face_scan';
  type: 'scan_button_click';
  data: null;
}

Slider interaction

All slider related events have event_component set to slider.

Slider Start

User activating slider

interface Event {
  component: 'slider';
  type: 'slider_button_click';
  data: {
    enabled: boolean;
  };
}
Slider Drag

User sliding the slider

interface Event {
  component: 'slider';
  type: 'slider_thumb_drag';
  data: {
    // slider position (ranging from 0 - 1 | left - right)
    position: number;
  };
}

Take-A-Photo

All photo related events have event_component set to photo.

Take-A-Photo Start

User activating take-a-photo

interface Event {
  component: 'photo';
  type: 'photo_button_click';
  data: null;
}
Close Photo Display

User closed photo display overlay

interface Event {
  component: 'photo';
  type: 'close_photo_button_click';
  data: null;
}
Photo Captured

Photo captured

interface Event {
  component: 'photo';
  type: 'photo_captured';
  data: null;
}

Product Selection

All product, range or look selection events have event_component set to products.

Product Selected

User selected a product

interface Event {
  component: 'products';
  type: 'select_product';
  data: {
    product: {
      // Unique CMS ID
      id: string;
      status: 'active' | 'inactive';
      schema: {};
      set: {};
      group: {};
      meta: {};
      region: {};
      data: {};
      rendering: {};
    };
  };
}
Range Selected

User selected a range

interface Event {
  component: 'products';
  type: 'select_range';
  data: {
    product: {
      // Unique CMS ID
      id: string;
      status: 'active' | 'inactive';
      schema: {};
      set: {};
      group: {};
      meta: {};
      region: {};
      data: {};
      rendering: {};
    };
  };
}
Filtered Product List

Filtered product list based on face-scan results

interface Event {
  component: 'products';
  type: 'filtered_products';
  data: {
    products: [];
  };
}
Product Information View Selected

User activated product info view

interface Event {
  component: 'products';
  type: 'info_view';
  data: {
    product: {
      // Unique CMS ID
      id: string;
      status: 'active' | 'inactive';
      schema: {};
      set: {};
      group: {};
      meta: {};
      region: {};
      data: {};
      rendering: {};
    };
  };
}
Look Information View Selected

User activated look info view

interface Event {
  component: 'products';
  type: 'info_view';
  data: {
    look: {
      self: {
        // Unique CMS ID for look
        id: string;
        schema: {};
        set: {};
        group: {};
        meta: {};
        region: {};
        status: 'active' | 'inactive';
        data: {};
        rendering: {};
      };
      // List of products included in look
      products: [];
    };
  };
}
Product Information View Closed

User closed product info view

interface Event {
  component: 'products';
  type: 'info_close';
  data: {
    product: {
      // Unique CMS ID
      id: string;
      status: 'active' | 'inactive';
      schema: {};
      set: {};
      group: {};
      meta: {};
      region: {};
      data: {};
      rendering: {};
    };
  };
}
Look Information View Closed

User closed look info view

interface Event {
  component: 'products';
  type: 'info_close';
  data: {
    look: {
      self: {
        // Unique CMS ID for look
        id: string;
        schema: {};
        set: {};
        group: {};
        meta: {};
        region: {};
        status: 'active' | 'inactive';
        data: {};
        rendering: {};
      };
      // List of products included in look
      products: [];
    };
  };
}
Product Added to Basket

User chose to add current product to basket

interface Event {
  component: 'products';
  type: 'add_basket';
  data: {
    product: {
      // Unique CMS ID
      id: string;
      status: 'active' | 'inactive';
      schema: {};
      set: {};
      group: {};
      meta: {};
      region: {};
      data: {};
      rendering: {};
    };
  };
}
Look Added to Basket

User chose to add current look to basket

interface Event {
  component: 'products';
  type: 'add_basket';
  data: {
    look: {
      self: {
        // Unique CMS ID for look
        id: string;
        schema: {};
        set: {};
        group: {};
        meta: {};
        region: {};
        status: 'active' | 'inactive';
        data: {};
        rendering: {};
      };
      // List of products included in look
      products: [];
    };
}
Look Selected

User selected a look

interface Event {
  component: 'products';
  type: 'select_look';
  data: {
    look: {
      self: {
        // Unique CMS ID for look
        id: string;
        schema: {};
        set: {};
        group: {};
        meta: {};
        region: {};
        status: 'active' | 'inactive';
        data: {};
        rendering: {};
      };
      // List of products included in look
      products: [];
    };
  };
}
Filter Selected

User selected a product filter

interface Event {
  component: 'products';
  type: 'select_filter';
  data: {
    filter:
      | 'blusher'
      | 'bronzer'
      | 'lipstick'
      | 'lipliner'
      | 'eyeshadow'
      | 'eyeliner'
      | 'foundation'
      | 'concealer'
      | 'eyebrow'
      | 'masacara';
  };
}

SDK Status

All SDK related events have event_component set to sdk.

SDK Initialised

SDK has initialised

interface Event {
  component: 'sdk';
  type: 'initialised';
  data: {
    status: boolean;
  };
}
Face Tracked

User face detected and tracked

interface Event {
  component: 'sdk';
  type: 'face_tracked';
  data: {
    status: boolean;
  };
}
Camera Access

Has user camera access been aquired

interface Event {
  component: 'sdk';
  type: 'camera_access';
  data: {
    status: boolean;
  };
}
Camera Feed Error

Camera has failed to start correctly

interface Event {
  component: 'sdk';
  type: 'feed_error';
  data: null;
}
Internal SDK Error

All internal FaceSDK errors - see SDK docuementation for more information

interface Event {
  component: 'sdk';
  type: 'error';
  data: {
    error: any;
  };
}
Critical Error

FaceSDK has experienced a critical error relating to hardware/browser incompatability.

interface Event {
  component: 'sdk';
  type: 'critical_error';
  data: {
    error: any;
  };
}
Info Button Clicked

General information button clicked

interface Event {
  component: 'sdk';
  type: 'info_button';
  data: null;
}

Static Image Upload

All image upload related events have event_component set to image_upload.

Select Image

User asked to select an image to upload

interface Event {
  component: 'image_upload';
  type: 'image_select';
  data: null;
}
Live Launch

SDK was launched with live camera view

interface Event {
  component: 'image_upload';
  type: 'live_launch';
  data: null;
}
Align Image

User clicked to button to align uploaded image (scale | flip | rotate)

interface Event {
  component: 'image_upload';
  type: 'image_align_click';
  data: {
    scale: number;
    flipV: boolean;
    flipH: boolean;
    rotate: number;
  };
}
Finish Alignment

User has finished aligning the image

interface Event {
  component: 'image_upload';
  type: 'finish_image_align';
  data: null;
}
Static Launch

SDK was launched with a static image

interface Event {
  component: 'image_upload';
  type: 'static_launch';
  data: null;
}

Actions

The iframe can be remotely controlled by sending actions in to it.

interface Action {
  command: string;
  data: any | null;
}

Set Product

Send the below action to set the active product

interface Action {
  command: 'set_product';
  data: {
    id: string;
    idType:
      | 'cms-id'
      | 'SKU'
      | 'EAN'
      | 'UPC'
      | 'GTIN'
      | 'ASIN'
      | 'Shade'
      | 'Range'
      | 'Other';
  };
}

Example:

// Set active product
function setProduct(productId, idType) {
  var win = document.getElementById('facesdk').contentWindow;
  const sendToFaceSdk = (action) =>
    win.postMessage(
      JSON.stringify(action),
      'https://holition-beauty-projects.holitionbeauty.com'
    );

  sendToFaceSdk({
    command: 'set_product',
    data: {
      id: productId,
      idType: idType,
    },
  });
}

Set Look

Send the below action to set the active look

interface Action {
  command: 'set_look';
  data: {
    id: string;
  };
}

Example:

// Set active look
function setLook(lookId) {
  var win = document.getElementById('facesdk').contentWindow;
  const sendToFaceSdk = (action) =>
    win.postMessage(
      JSON.stringify(action),
      'https://holition-beauty-projects.holitionbeauty.com'
    );

  sendToFaceSdk({
    command: 'set_look',
    data: {
      id: lookId,
    },
  });
}

Data Loaded

FaceSDK has loaded product data correctly

interface Event {
  component: 'sdk';
  data: null;
  type: 'data_loaded';
}