## DeviceAtlas Device Verification QR Code This guide explains how to integrate DeviceAtlas Device Verification QR codes into your website. When scanned with a mobile device, the QR code triggers device verification and returns results to your page. ## Table of Contents - [Quick Start](#quick-start) - [Methods](#methods) - [DeviceAssure.qr()](#devicevalidationqr) - [DeviceAssure.parseQrRedirect()](#devicevalidationparseqrredirect) - [Configuration Options](#configuration-options) - [Response Format](#response-format) - [Examples](#examples) - [Basic Setup](#basic-setup) - [With Callback](#with-callback) - [Device Redirect](#device-redirect) - [Host Redirect](#host-redirect) - [Auto-Refresh](#auto-refresh) - [Custom Destination](#custom-destination) - [IMEI Corroboration](#imei) - [Custom Tags](#custom-tags) - [Styling](#styling) - [Troubleshooting](#troubleshooting) - [Redirect URLs](#troubleshooting-redirect-urls) - [Content Security Policy](#troubleshooting-csp) - [Callback Naming](#troubleshooting-callback-naming) --- <h2 id="quick-start">Quick Start</h2> ```html <div id="deviceassure-qr-container"></div> <script src="/path/to/deviceassure.min.js" onload="setupQR()" defer></script> <script> function setupQR() { DeviceAssure.qr({ containerId: 'deviceassure-qr-container', licence: '<YOUR_LICENCE_KEY>', callback: function(result) { console.log('Scan result:', result); } }); } </script> ``` --- <h2 id="methods">Methods</h2> <h3 id="devicevalidationqr">DeviceAssure.qr()</h3> Generates and displays a QR code in the specified container. ```javascript DeviceAssure.qr({ containerId: 'deviceassure-qr-container', // The div to insert the QR code iframe into licence: '<YOUR_LICENCE_KEY>', callback: function(result) { console.log(result); }, imei: '<YOUR_IMEI_VALUE>', tags: [ { key: 'customTag1', value: 'value1' }, { key: 'customTag2', value: 'value2' } ], size: 250, json: false, scannedMessage: 'Code was scanned', expiredMessage: 'Code has expired', lifecycle: 'default', responseDelay: 2000, redirect: 'https://example.com/host-redirect', deviceRedirect: 'https://example.com/device-redirect', destination: 'https://example.com/custom-destination', script: { defer: true, async: true, nonce: 'randomNonceValue' } }); ``` <h3 id="devicevalidationparseqrredirect">DeviceAssure.parseQrRedirect()</h3> Parses the base64-encoded response from a redirect URL. | Parameter | Type | Default | Description | |----------------|---------|---------|---------------------------------------------------------------------------------------------------------------------| | `data` | string | | Base64 string representing the JSON response. If not provided, the `response` query parameter from the URL is used. | | `options.json` | boolean | `false` | When `true`, returns the parsed JSON object. When `false`, returns the decoded string. | ```javascript // Processes the response query parameter and returns a string DeviceAssure.parseQrRedirect(); // Processes the response query parameter and returns an object DeviceAssure.parseQrRedirect(null, { json: true }); // Processes the passed in base64 string and returns a string DeviceAssure.parseQrRedirect('eyJjb2RlIjoi...'); // Processes the passed in base64 string and returns an object DeviceAssure.parseQrRedirect('eyJjb2RlIjoi...', { json: true }); ``` --- <h2 id="configuration-options">Configuration Options</h2> | Parameter | Type | Default | Description | |------------------|----------|-----------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | `containerId` | string | `deviceassure-qr-container` | ID of the container element for the QR code iframe | | `licence` | string | | Your DeviceAssure licence key for accessing licence-specific device properties and configurations. | | `callback` | function | | Function called when a scan result is received | | `size` | number | `250` | QR code size in pixels (min: 50, max: 500) | | `json` | boolean | `false` | When `true`, hides the iframe after scan and returns data via callback | | `scannedMessage` | string | `Code was scanned` | Message displayed after successful scan | | `expiredMessage` | string | `Code has expired` | Message displayed when QR code expires | | `lifecycle` | string | `default` | `default`: shows scanned message after scan. `auto-refresh`: automatically generates new code once scanned | | `responseDelay` | number | `2000` | The time delay after a scan. Usually used in conjunction with the `auto-refresh` lifecycle and host `redirect` in order to show a message before transitioning. | | `redirect` | string | | URL to redirect the host page after scan | | `deviceRedirect` | string | | URL to redirect the scanning device after scan | | `imei` | string | | Provide an IMEI for use as another identifier for device verification. When `imei` is provided, it must be a non-empty string containing a valid IMEI. | | `tags` | array | `[]` | A list of tags to add to the API request. Allows for custom parameters to be returned in the API Response. The `key` and `value` must be strings. <br> Maximum length for keys and values is 64 and 128 respectively | | `script.defer` | boolean | false | Injects the `defer` attribute | | `script.async` | boolean | false | Injects the `async` attribute | | `script.nonce` | string | | Adds a `nonce` to the script | --- <h2 id="response-format">Response Format</h2> ### Callback Response When using the `callback` option, results are returned in this format: ```json { "type": "com.deviceassure.payload.result", "data": { "code": "bd3f41f0-ace0-4c77-ae33-da195f2675ff", "deviceAssure": { "result": "AUTHENTIC", "reason": "Properties match", "deviceAtlasProperties": { "vendor": "Google", "marketingName": "Pixel 6a" }, "referenceId": "871d26e2-94fb-400a-92ab-3b9a672b4c53" }, "meta": {} } } ``` | Property | Type | Description | |----------|------|-------------| | `type` | string | Response type: `com.deviceassure.payload.result`, `com.deviceassure.payload.redirect`, or `com.deviceassure.payload.reload` | | `data.code` | string | Unique QR code identifier | | `data.deviceAssure` | object | Device verification result (see Implementation Guide for details) | ### Redirect Response When using `redirect` or `deviceRedirect`, the target URL receives a `response` query parameter containing a base64-encoded JSON string: ``` https://example.com/redirect?response=eyJjb2RlIjoiYmQzZjQx... ``` The decoded response has a flattened structure (no `type` or `data` wrapper): ```json { "code": "bd3f41f0-ace0-4c77-ae33-da195f2675ff", "deviceAssure": { "result": "AUTHENTIC", "reason": "Properties match", "deviceAtlasProperties": { "vendor": "Google", "marketingName": "Pixel 6a" }, "referenceId": "871d26e2-94fb-400a-92ab-3b9a672b4c53" }, "meta": {} } ``` --- <h2 id="examples">Examples</h2> <h3 id="basic-setup">Basic Setup</h3> This example will: - Display a QR code with default settings - Show standard scan/expired messages in the iframe ```html <div id="deviceassure-qr-container"></div> <script src="/path/to/deviceassure.min.js" onload="setupQR()" defer></script> <script> function setupQR() { DeviceAssure.qr({ containerId: 'deviceassure-qr-container', licence: '<YOUR_LICENCE_KEY>' }); } </script> ``` <h3 id="with-callback">With Callback</h3> This example will: - Display a 300px QR code - Hide the iframe after scan (`json: true`) - Call the callback function with the scan result - Display the result on the page ```html <div id="deviceassure-qr-container"></div> <div id="result"></div> <script src="/path/to/deviceassure.min.js" onload="setupQR()" defer></script> <script> function setupQR() { DeviceAssure.qr({ containerId: 'deviceassure-qr-container', licence: '<YOUR_LICENCE_KEY>', callback: function(result) { var deviceAssure = result.data.deviceAssure; document.getElementById('result').innerHTML = deviceAssure.result + ': ' + deviceAssure.reason; }, size: 300, json: true }); } </script> ``` <h3 id="device-redirect">Device Redirect</h3> This example will: - Display a QR code on the host page - Redirect the scanning device to a results page after scan - Pass the scan result as a base64-encoded `response` query parameter - The redirect page parses and displays the result **Host Page:** ```html <div id="deviceassure-qr-container"></div> <script src="/path/to/deviceassure.min.js" onload="setupQR()" defer></script> <script> function setupQR() { DeviceAssure.qr({ containerId: 'deviceassure-qr-container', licence: '<YOUR_LICENCE_KEY>', deviceRedirect: 'https://example.com/device-result' }); } </script> ``` **Redirect Page (device-result):** ```html <div id="result"></div> <script src="/path/to/deviceassure.min.js" onload="showResult()" defer></script> <script> function showResult() { // Parse the response query parameter as a JSON object const result = DeviceAssure.parseQrRedirect(null, { json: true }); document.getElementById('result').innerHTML = JSON.stringify(result, null, 2); } /** * Alternatively, if you want to get the result as a string instead of an object, you can use the following code: */ function showResultAsString() { const result = DeviceAssure.parseQrRedirect(); console.log('Decoded DeviceAssure result from redirect:', result); } /** * Alternatively, if the base64 string is known, you can pass it in directly as follows: */ function parseKnownBase64(base64String) { const result = DeviceAssure.parseQrRedirect(base64String, { json: true }); console.log('Decoded DeviceAssure result from redirect:', result); } </script> ``` **Alternative without DeviceAssure library:** ```html <script> // Get the value of the 'response' parameter from the URL var urlParams = new URLSearchParams(window.location.search); var encodedData = urlParams.get('response'); // Decode the base64 string and display the DeviceAssure response document.getElementById('json-div').innerHTML = atob(encodedData); </script> ``` <h3 id="host-redirect">Host Redirect</h3> This example will: - Display a QR code on the host page - Redirect the host page (desktop) to a results page after scan - Pass the scan result as a base64-encoded `response` query parameter - The redirect page parses and displays the result ```html <div id="deviceassure-qr-container"></div> <script src="/path/to/deviceassure.min.js" onload="setupQR()" defer></script> <script> function setupQR() { DeviceAssure.qr({ containerId: 'deviceassure-qr-container', licence: '<YOUR_LICENCE_KEY>', redirect: 'https://example.com/host-result' }); } </script> ``` > **Note:** The redirect page handling is the same as [Device Redirect](#device-redirect). <h3 id="auto-refresh">Auto-Refresh</h3> This example will: - Display a QR code on the host page - Show a custom "Device verified!" message after scan - Wait 2000ms then automatically generate a new QR code - Call the callback function with each scan result ```html <div id="deviceassure-qr-container"></div> <script src="/path/to/deviceassure.min.js" onload="setupQR()" defer></script> <script> function setupQR() { DeviceAssure.qr({ containerId: 'deviceassure-qr-container', licence: '<YOUR_LICENCE_KEY>', callback: function(result) { console.log('Scan result:', result); }, lifecycle: 'auto-refresh', responseDelay: 2000, scannedMessage: 'Device verified!' }); } </script> ``` <h3 id="imei">IMEI Corroboration</h3> The `imei` can be added as a parameter to the QR code generation. This allows the IMEI to be used as an additional identifier for device verification. An example implementation is shown below: ```html <div id="deviceassure-qr-container"></div> <script src="/path/to/deviceassure.min.js" onload="setupQR()" defer></script> <script> function setupQR() { DeviceAssure.qr({ containerId: 'deviceassure-qr-container', licence: '<YOUR_LICENCE_KEY>', imei: '<YOUR_IMEI_VALUE>', callback: function(result) { console.log('QR message:', result); } }); } </script> ``` <h3 id="custom-tags">Custom Tags</h3> The `tags` can be added as a parameter to the QR code generation. This allows for custom tags to be returned in the response for further use. An example implementation is shown below: ```html <div id="deviceassure-qr-container"></div> <script src="/path/to/deviceassure.min.js" onload="setupQR()" defer></script> <script> function setupQR() { DeviceAssure.qr({ containerId: 'deviceassure-qr-container', callback: function(result) { console.log('QR message:', result); }, licence: '<YOUR_LICENCE_KEY>', tags: [ { key: 'page', value: 'imei-validation' }, { key: 'campaign', value: 'spring-sale' } ] }); } </script> ``` <h3 id="custom-destination">Custom Destination</h3> The `destination` can be added a parameter to the QR code generation. This controls where the QR code 'points' to. It is useful when wanting to point to a custom page rather than the default DeviceAssure page. This can be used in conjunction with the `redirect` and `deviceRedirect` parameters to control the flow of the QR code. This page will need to collect the payload and send it on to our API in order to get the device verification result. The `destination` can be used to point to this page and the `redirect` and `deviceRedirect` can be used to control where the host and scanning device go after the scan respectively. **Note:** The `deviceRedirect` implementation will need to be handled in the custom page the QR points to. However, the message returned to this page will contain the redirect url for use. An example implementation is shown below: ```html <div id="deviceassure-qr-container"></div> <script src="/path/to/deviceassure.min.js" onload="setupQR()" defer></script> <script> function setupQR() { DeviceAssure.qr({ containerId: 'deviceassure-qr-container', licence: '<YOUR_LICENCE_KEY>', destination: 'https://deviceatlas.com/deviceassure?this-is-query-param=will-be-included-too', callback: function(result) { console.log('QR message:', result); }, }); } </script> ``` ###### Example Destination Page Implementation Below shows how to collect and send the payload to the DeviceAtlas QR API. The payload will be collected by the `DeviceAssure.load()` function and then sent to the API using `fetch()`. The QR code ID is needed to correlate the device and the qr code. It is passed in to the url via a query parameter when the QR code is scanned. This can be extracted and included in the header of the API request for correlation purposes. Example URL: ```http request https://localhost:8091/deviceassure?deviceatlas-qr-code=bd3f41f0-ace0-4c77-ae33-da195f2675ff&other-parameters=you-can-include ``` ```html <script src="/path/to/deviceassure.min.js" onload="sendApiRequest()" defer></script> <script type="application/javascript"> function sendApiRequest() { DeviceAssure.load({ serverToServer: true, onError: function (error) { console.error('DeviceAssure Library failed to collect:', error); }, onSuccess: async function (payload) { try { const qrCodeId = (new URLSearchParams(window.location.search)).get('deviceatlas-qr-code'); const options = { method: 'POST', body: JSON.stringify(payload), headers: { 'Content-Type': 'application/json', 'X-Device-Assure-Reference-Id': qrCodeId // include the QR code ID in the header for correlation purposes } }; const response = await fetch(`https://qr-code.deviceatlas.com/v2/check/${qrCodeId}`, options); if (response.status >= 400) { console.error('Non 200 response from DeviceAssure', await response.json()); } else { console.log('Successfully sent payload to DeviceAssure', await response.json()); } } catch (e) { console.error('An error occurred calling DeviceAssure', e); } } }) } </script> ``` --- <h2 id="styling">Styling</h2> Customize the QR code iframe appearance with CSS: ```css /* Size the iframe */ #deviceassure-iframe { width: 325px; height: 325px; } /* Center the QR code container */ #deviceassure { display: flex; justify-content: center; align-items: center; } ``` --- <h2 id="troubleshooting">Troubleshooting</h2> <h3 id="troubleshooting-redirect-urls">Redirect URLs</h3> When using `redirect` or `deviceRedirect`, the URL must be accessible from the scanning device. The following will **not** work: - `localhost` - `127.0.0.1` - `0.0.0.0` Use a network IP address or domain name accessible to the scanning device. <h3 id="troubleshooting-csp">Content Security Policy (CSP)</h3> If your site uses a Content Security Policy (CSP), ensure that the following domains are allowed: - `qr-code.deviceatlas.com` (Iframe) - `cdn.devicevalidation.io` (Web Library Scripts) An Example setup could look like: ```http Content-Security-Policy: frame-src 'self' https://qr-code.deviceatlas.com; script-src 'self' https://cdn.devicevalidation.io https://qr-code.deviceatlas.com; ``` The DeviceAssure API url might need to be added to the CSP too. The following urls might need to be configured too: - `https://api1.devicevalidation.io` - `https://api2.devicevalidation.io` - `https://api3.devicevalidation.io` These can be set in the CSP by: ```http Content-Security-Policy: connect-src 'self' https://api1.devicevalidation.io https://api2.devicevalidation.io https://api3.devicevalidation.io; ``` A full CSP for DeviceAssure could look like: ```http Content-Security-Policy: frame-src 'self' https://qr-code.deviceatlas.com; connect-src 'self' https://api1.devicevalidation.io https://api2.devicevalidation.io https://api3.devicevalidation.io; script-src 'self' https://cdn.devicevalidation.io https://qr-code.deviceatlas.com; ``` <h3 id="troubleshooting-callback-naming">Callback Naming</h3> When using `DeviceAssure.qr()`, your callback can have any name — the library internally wires it to the global `_deviceAssureResultReceived` function. However, if you use the raw snippet directly (without the library wrapper), you **must** define the callback with the exact name `_deviceAssureResultReceived`: ```html <script src="https://qr-code.deviceatlas.com/v2/api/snippet.js?dv-licenceKey=<YOUR_LICENCE_KEY>"></script> <script> function _deviceAssureResultReceived(result) { console.log('Result:', result); } </script> ``` --- ## Copyright Copyright (c) DeviceAtlas Limited 2026. All rights reserved. https://deviceatlas.com