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.
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.
The following are the minimum specifications required to operate:
Mobile
Desktop
WebGL 1+
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.
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.
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.
To control the look and feel of the virtual experience either:
[NB. URL parameters take priority over CMS settings]
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>
DEPLOYMENT-URL
- (required)
Link to a release you want, please see the release tab for these.cms-client-id
- (required)
This is the id of your client on the calibration portal cms. This is where product information is pulled from. Info can be found in the Portal Guidelicense
- (required)
The sdk requires a license to use.identifier-type
- (optional)
The type of product or look identifier "cms-id" | "SKU" | "EAN" | "UPC" | "GTIN" | "ASIN" | "Shade" | "Range" | "Other"
identifier-value
- (optional)
The product or look identifier valuerange-id
- (optional)
The product or look range identifier (found in CMS) used to limit product displayrange-name
- (optional)
Lookup the product or look range by name field filteringlooks
- (optional)
Switch between using looks and products (true | false)features
- (optional)
enable control buttons (all | photo | slider | image)carousel
- (optional)
enable product carousel (true | false)filter
- (optional)
enable product type filter swiper (true | false)configuration-id
- (optional)
overrides the default ui config with one from the holition beauty portal, url parameters still take priority over this configproduct-info
- (optional)
show product information panel and button in carousel (true | false)look-info
- (optional)
show look information panel and button in carousel (true | false)add-basket
- (optional)
show “add to basket” button on product information panel (true | false)watermark
- (optional)
show the Holition Beauty watermark (true | false)vtoggle
- (optional)
toggle visibility of looks and products filter bar (true | false)info-button
- (optional)
toggle general info button display (true | false)simplify-carousel-info
- (optional)
toggle simplification of product info display (true | false)static-start
- (optional)
toggle launch option for static or live camera view (true | false)locale
- (optional)
sets locale of the page, this will determine what text is displayed from the portal cms, defaults to “en”, can be any of:"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"
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]
The web-app allows for both dynamic control (actions) and real-time event reporting (events) to and from the parent host page.
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: any | null;
}
All face-scan related events have event_component
set to face_scan
.
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;
};
};
}
The progress of the face-scan
interface Event {
component: 'face_scan';
type: 'scan_progress';
data: {
progress: number;
};
}
User has started the face scan experience
interface Event {
component: 'face_scan';
type: 'scan_button_click';
data: null;
}
All slider related events have event_component
set to slider
.
User activating slider
interface Event {
component: 'slider';
type: 'slider_button_click';
data: {
enabled: boolean;
};
}
User sliding the slider
interface Event {
component: 'slider';
type: 'slider_thumb_drag';
data: {
// slider position (ranging from 0 - 1 | left - right)
position: number;
};
}
All photo related events have event_component
set to photo
.
User activating take-a-photo
interface Event {
component: 'photo';
type: 'photo_button_click';
data: null;
}
User closed photo display overlay
interface Event {
component: 'photo';
type: 'close_photo_button_click';
data: null;
}
Photo captured
interface Event {
component: 'photo';
type: 'photo_captured';
data: null;
}
All product, range or look selection events have event_component
set to products
.
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: {};
};
};
}
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 based on face-scan results
interface Event {
component: 'products';
type: 'filtered_products';
data: {
products: [];
};
}
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: {};
};
};
}
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: [];
};
};
}
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: {};
};
};
}
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: [];
};
};
}
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: {};
};
};
}
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: [];
};
}
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: [];
};
};
}
User selected a product filter
interface Event {
component: 'products';
type: 'select_filter';
data: {
filter:
| 'blusher'
| 'bronzer'
| 'lipstick'
| 'lipliner'
| 'eyeshadow'
| 'eyeliner'
| 'foundation'
| 'concealer'
| 'eyebrow'
| 'masacara';
};
}
All SDK related events have event_component
set to sdk
.
SDK has initialised
interface Event {
component: 'sdk';
type: 'initialised';
data: {
status: boolean;
};
}
User face detected and tracked
interface Event {
component: 'sdk';
type: 'face_tracked';
data: {
status: boolean;
};
}
Has user camera access been aquired
interface Event {
component: 'sdk';
type: 'camera_access';
data: {
status: boolean;
};
}
Camera has failed to start correctly
interface Event {
component: 'sdk';
type: 'feed_error';
data: null;
}
All internal FaceSDK errors - see SDK docuementation for more information
interface Event {
component: 'sdk';
type: 'error';
data: {
error: any;
};
}
FaceSDK has experienced a critical error relating to hardware/browser incompatability.
interface Event {
component: 'sdk';
type: 'critical_error';
data: {
error: any;
};
}
General information button clicked
interface Event {
component: 'sdk';
type: 'info_button';
data: null;
}
All image upload related events have event_component
set to image_upload
.
User asked to select an image to upload
interface Event {
component: 'image_upload';
type: 'image_select';
data: null;
}
SDK was launched with live camera view
interface Event {
component: 'image_upload';
type: 'live_launch';
data: null;
}
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;
};
}
User has finished aligning the image
interface Event {
component: 'image_upload';
type: 'finish_image_align';
data: null;
}
SDK was launched with a static image
interface Event {
component: 'image_upload';
type: 'static_launch';
data: null;
}
The iframe can be remotely controlled by sending actions in to it.
interface Action {
command: string;
data: any | null;
}
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,
},
});
}
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,
},
});
}