The Web Application

The consumer value of all this account setup is the ability to scan a QR code on the product packaging and receive a personalized (or localized or both) experience that rewards them for interacting with the product after it's purchased. The final piece that makes this possible is the web app itself.

The brand that produces the product controls the experience and can add or remove content at any time without needing to print new packaging. Additional EVRYTHNG features, such as the Redirector can make this personalization even deeper and more relevant to each user.

In general, the web app uses the scanthng.js SDK to authenticate as the previously created application resource, and creates an anonymous Application User representing the consumer to allow the creation of actions of the previously created custom action types.


Using the SDK

To begin using the scanthng.js SDK in a web application, include a specific version of the SDK distribution near the end of your page's body tag. For example, a simple page could begin like this when it includes the SDK libraries:

<!DOCTYPE html>
<html>
  <head>
    <title>Scan App Test</title>
  </head>
  <body>
    ...
    <!-- Include evrythng.js -->
    <script src="https://d10ka0m22z5ju5.cloudfront.net/js/evrythng/5.2.0/evrythng-5.2.0.js"></script>

    <!-- Include scanthng.js -->
    <script src="https://d10ka0m22z5ju5.cloudfront.net/js/scanthng/4.0.0/scanthng-4.0.0.js"></script>

    <!-- The application script -->
    <script src="./script.js"></script>
  </body>
</html>

📘

Note

Always ensure you include a specific version of the SDK so that upgrades can be managed more easily in the future.

In the web application script, create an Application scope using the application's Application API Key (appApiKey), returned in Creating an Application.

const APPLICATION_API_KEY = 'ej05OmVh...';

// Add the scanthng.js plugin to evrythng.js
evrythng.use(ScanThng);

// Create an App scope to allow limited access to EVRYTHNG data
const app = new evrythng.Application(APPLICATION_API_KEY);

This app scope is used to perform all other web app-related functionality, which is discussed below. This is the application resource's primary purpose.


Perform a Scan

Use the newly created app object to launch a scan using the scan() method. Depending on the device, this either opens the camera view to take a photo or asks the user to choose an existing photo. This occurs as soon as scan() is called.

It is important to note that scan() must be called as a result of user interaction, such as on a button press. An example button is shown below:

<input type="button" id="button-scan" value="Click to Scan"/>
function onScanSuccess(response) {
  // Do something on success
  console.log(response);
}

function onScanError(err) {
  // Do something on error
  console.log(err);
}

function onButtonClick() {
  // Initiate the scan
  app.scan()
    .then(onScanSuccess)
    .catch(onScanError);
}

const buttonScan = document.getElememtById('button-scan');
buttonScan.addEventListener('click', onButtonClick);

If the scan is successful, the response object contains an array of results, each representing an EVRYTHNG product or Thng that was matched with the submitted image, if any.

The example implementation of onScanSuccess below shows how to use the response to determine which resource was found, and to determine the redirection associated with it:

function onScanSuccess(response) {
  if (!response.length) {
    throw new Error('No value was decoded');
  }
  
  if (!response[0].results.length) {
    throw new Error('No results found!');
  }
  
  // Report the first matching Thng (could also be 'product')
  const [first] = response[0].results;
  console.log(`Thng: ${first.thng.id}`);
  console.log(`Redirection: ${first.redirections[0]}`);
}

To record the successful scan, the application can create an action of the built-in type scans as a response to the initial implicitScan action automatically created when the redirection is followed:

// Record the successful scan
app.action('scans').create({ thng: firstResult.thng.id });

Using the Action Types

Now that the scan can be initiated, and various outcomes detected, the evrythng.js SDK can also be used to create actions of the previously defined action types so you can track engagement progress in more detail than the built-in action types permit. This is done in the next section using EVRYTHNG Dashboard customizable widgets.

Widgets can be created using the evrythng.js SDK on behalf of the application by using an anonymous Application User that has special access to any additional action types in the project's scope:

app.appUser().create({ anonymous: true })
  .then((anonymousUser) => {
    // Use the anonymous Application User here
  });

Creating widgets this way is useful to report that a scan took place but that no EVRYTHNG resources were associated with the submitted image, using the _ProductNotFound example action type:

// If no results in the response
if (!response[0].results.length) {
  // Report that the scan occurred, but that no product was found
  return anonymousUser.action('_ProductNotFound').create();
}

This example handles cases where the scan failed outright due to some other error surfaced by the scan() SDK method with the _ScanFailed example action type:

function onScanError(err) {
  // Report the scan failed to take place
  const action = {
    customFields: {
      message: JSON.stringify(err),
    },
  };

  anonymousUser.action('_ScanFailed').create(action)
    .then(console.log);
}

Providing the Experience

After the user has scanned a valid QR code (or similar barcode) and the SDK has identified the product or Thng it is associated with, the redirection will provide the user with the brand consumer engagement experience.

The last step is simple—use the redirect() method with the scan result's redirections string:

// Record the event
anonymousUser.action('_RedirectionFollowed').create()
  // then redirect to the experience
  .then(() => app.redirect(first.redirections[0]));

Alternatively, this mechanism can be used to redirect the user to a page that gives them more information on remedying an error or instructs them to attempt the scan again.

const TRY_AGAIN_URL = 'https://supercrunchy.cereal/scan/try_again';

function onScanError(err) {
  // Report the scan failed to take place
  const action = {
    customFields: {
      message: JSON.stringify(err),
    },
  };

  anonymousUser.action('_ScanFailed').create(action)
    .then(console.log)
    .then(() => app.redirect(TRY_AGAIN_URL));
}

Handling Third-party Scanners

When a user uses the web application that includes the evrythng.js SDK, the SDK identifies the Thng or product the user scanned, but if the user scans the QR code with a third-party scanner, this information is not available automatically.

To realign with the first case, we recommend you include the Thng or product's ID in the redirect URL as a query parameter. This way, after the web application has loaded, it can use this value to create actions on the correct resource corresponding to the real-world item that was scanned. This can be easily done by including the template {thngId} in the Thng redirection.


Complete Example

You can build a bare-essentials example scanning web app using the example snippets above, or see the full example app on GitHub.