The Web Application

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

The brand that produces the product are the ones that will control the experience, and can add or remove content at any time without the need to print new packaging. Using additional EVRYTHNG features such as the Redirector can make this personalization even deeper and more relevant to each individual user.

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


Using the SDK

To begin using the SDK in a web application, include a specific version of the SDK distribution towards 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, noted earlier.

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 will be used to perform all other web app-related functionality, which will be discussed below. This is the application resource's primary purpose, among others.


Perform a Scan

Use the newly created app object to launch a scan using the scan() method. Depending on the device, this will either open the camera view to take a photo, or ask the user to choose a photo they shot earlier, or some choice between these. 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. Such an example element that could be used 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 was successful, the response object will contain 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 fact that the scan was a success, the application may create an action of the built-in type scans, as a follow up 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 itself can be initiated, and various outcomes detected, the evrythng.js SDK can also be used to create actions of the previously defined action types to allow you to track engagement progress (both good and bad) in more detail than the main built-in action types permit. This will be done in the next section using EVRYTHNG Dashboard customizable widgets.

These can be created using the evrythng.js SDK on behalf of the application 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
  });

This is useful in this use-case to report that a scan took place, but that no EVRYTHNG resources were found to be 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();
}

Or that 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

Once 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.

Using the SDK, this last step is simple - using 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 giving them more information on remedying an error, or instructing 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 including the evrythng.js SDK, the SDK takes care of identifying the Thng or product that was scanned by the user, but if the user scans the QR code with a third-party scanner, this information is not available automatically.

To re-align with the first case, it is recommended to include the Thng or product's ID in the redirect URL as a query parameter. This way, once 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 check out the full example app on GitHub.