This is an old revision of the document!


Visitor Identity and Tracking

A Visitor Spot in Blocks can be used as a basic entry point for visitors to connect to the system. This is essentially a URL allowing a number of visitors to all connect to the same Visitor Spot. The URL looks something like this:

https://pixi.guide/spot?mobile=Mob1

Where the protocol (http or https) and domain name (or IP address) parts vary depending on how your Blocks server is configured. The name following ?mobile= is the name of the Visitor Spot. Often, such a URL is specified as the default URL for your Blocks server in the server configuration file, like this:

# Where to go if addressing root of server (i.e., just http://pixi.guide/)
serverRootRedirect: /spot/?mobile=Mob1

If you have something like this in your configuration file, it's sufficient for visitors to enter just the domain name in their browser, i.e.

pixi.guide

Anonymous versus Identified Visitors

Such a Visitor Spot can be configured either in an anonymous or visitor-specific manner. This is controlled by the "Identify Individual Visitors" setting under the Identity tab of the Visitor Spot's settings.

If "Identify Individual Visitors" is not selected, Blocks does not provide the ability to control or track individual visitors. You still have limited, collective control over some basic aspects, such as which root block being presented.

By selecting "Identify Individual Visitors" you gain two important abilities:

  1. For each individual visitor, independent control over child blocks, parameters, tags, custom CSS classes, etc, similar to what you have for Display Spots.
  2. The ability to collect time-stamped data on each individual visitor, such as any data being entered by that visitor, spots being visited, scores of games, etc.

By combining these two abilities, you can do things such as presenting different content to a visitor depending on where she's been during her visit, points earned along the way, or any other data provided or collected during the visit. Such data can also be archived after the visit for subsequent analyzation, e.g. to understand the route taken by visitors, which exhibits they visited, how long they stayed there, etc.

Means of Identification

When using individual visitor identification, Blocks supports a number of ways by which visitors can be identified:

  1. Using their mobile phone as the only identification.
  2. Using an identification tag, such as an RFID bracelet handed out at the reception.
  3. A combination of the above, where the RFID bracelet acts as the primary identification, and an optional mobile device can be associated with the same visitor for interaction and feedback purposes.
  4. Pre-qualified visitors, where each visitor is given a unique log-in code ahead of time (e.g., in an email). Additional data on visitor (such as name, company, etc) is pre-loaded into Blocks, and only pre-qualified visitors can gain access.

Using Mobile Phone as Only Identification

This is the easiest and most straightforward method of identifying and interacting with the visitor. It typically uses a Locator block to determine the whereabouts of the visitor, presenting relevant content and interaction at each spot along the way.

To use this method, do as follows:

  1. Create a Blocks user script (see below) defining the type of data to record.
  2. Select "Identify Individual Visitors" as discussed above.
  3. Enter the name of the data record in the "Record type" field.

Using an Identification Token

Here, a unique identification token is handed out to each visitor at the entrance. This token could for example be an RFID bracelet och tag, carried by the visitor. By scanning this token at desired stations, Blocks will learn who's where, and can collect and act on this information. The token may be returned when leaving, and recycled for new visitors.

This arrangement removes the need for visitors to have and use a personal mobile phone. Depending on the information collected during the visit, this may also remove any privacy issues (assuming no personally identifiable information is collected). More on this below.

The visitor can still have a personalized experience, based on where she's been or interactions performed or information entered at visited spots. Personalized information can be presented on Display Spots as the visitor presents the identification token (e.g., scans the RFID bracelet).

To use this method, do as follows:

  1. Create a Blocks user script (see below) defining the type of data to record.
  2. Select "Identify Individual Visitors" as discussed above.
  3. Enter the name of the data record in the "Record type" field.
  4. Connect the desired number of token scanners (RFID, or similar) to Blocks.
  5. Scan the token when handing it out to the visitor.
  6. In the user script, create the visitor's data record, associating it with the token's ID.

Now, as the visitor scans the token at desired spots, Blocks will learn about this and can take actions as desired (including presenting personalized interactions at display spots).

To scan the tokens, you can use either stand-alone scanners connected to the network, managed by a Device Driver in Blocks. Or use a Display Spot with a keyboard-emulating scanner connected to its USB port. Set the Display Spot to use "RFID/QR Keyboard Input" in its Advanced tab.

IMPORTANT: If tokens are reused, make sure tokens are disassociated from their visitors. This can be done in one or more of the following means:

  • When returned at the exit, by canning it in a specific "exit scanner".
  • When handed out to another visitor.
  • En masse, for all tokens, once every night. This method assumes tokens aren't re-used the same day.

Using a Combination of Token and Mobile Phone

This method is essentially the same as the previous one, but with the additional ability of also associating a mobile phone with the same visitor. This may allow for basic tracking and personalized experience using the token, while using an (optional) mobile phone to augment the experience, acting as a personal point of interaction and feedback.

To use this method, do as follows:

  1. Create a Blocks user script (see below) defining the type of data to record.
  2. Select "Identify Individual Visitors" as discussed above.
  3. Enter the name of the data record in the "Record type" field.
  4. Select "Mobile is Secondary ID", and enter the name of a record field marked with @id().
  5. Connect the desired number of token scanners to Blocks.
  6. Scan the token when handing it out to the visitor.
  7. In the user script, create the visitor's data record, associating it with the token's ID.
  8. Optionally, also scan the visitors mobile phone. This can be done using a QR code shown on the phone. This links the mobile phone to the same data record as identified by the token.

You'll then use the token at each station to identify yourself. The optional mobile phone can be used as feedback (e.g., scores at game stations) or to enter information that will then go into the visitor's data record and/or be directly acted upon by the user script.

Privacy Issues

Depending on what information you collect and the jurisdiction in your country, you may need to pay attention to privacy regulations, such as europe's GDPR law. This can be handled by presenting a notice on visitors' mobile devices that must be agreed to before proceeding, or similar.

User Script

To utilize the individual visitor tracking and interaction capabilities, you need a Blocks user script. This script defines the data that may be collected. It also decides what will happen as visitors arrive at interaction spots.

Data Record Declaration

A key function of the user script is to declare what data to be collected from visitors. This is done using a record declaration, typically located at the beginning of the script. Such a declaration could look line this:

@record("Data we track for each visitor")
class ExampleRecord extends RecordBase {
    @field() whenJoined: number;	// Time when first connected
    @field() station: string;	// Currently (or last) visited station
    @field() heardSound: boolean;	// The visitor has been at the sound station
    @field() @spotParameter() visitorName: string; // Visit's desired nickname
    @field() @spotParameter() quizScore: number;   // Score in our Quiz game
}

The name of this record type is "ExampleRecord". That's the name to enter in the "Record type" field of the Identity tab in the Visitor Spot's settings. The declaration shown above has five data fields. What data fields to use and what they're called depends entirely on what data you want to collect. Each data field must be marked with the @field() decorator.

In addition to the fields shown above, each record also has a unique identification number named $puid, which is declared in the RecordBase base class, which all custom record declarations must extend. This $puid number can be used to uniquely identify each data record. When using the visitors mobile phone as the only identification, this matches the identity ID assigned to the phone when it first connects to Blocks through this mobile spot's URL.

Record Field Decorators

As mentioned above, each field in the record must be marked with the @field() decorator, as you can see above. In addition to this mandatory decorator, you may use the following optional decorators:

  • @spotParameter() marks the field as an alias of a Spot Parameter.
  • @id() marks the field as holding a unique value that can be used to identify the record.

The @spotParameter() decorator causes data stored in the record to be linked to a spot parameter with the same name. You must establish this spot parameter separately, making sure it has the same name and data type as the record field. This can be done either in the Block to be used by the Visitor Spot, or on the Visitor Spot itself (on the Parameters tab of the Visitor Spots settings). Once you've linked the record field to a spot parameter in this way, any changes made to the parameter will be reflected in the data record field and vice versa.This could, for example, be used to allow your visitor to enter a nickname, or other relevant information, that you then want to persist in the visitor's data record.

The @id() decorator indicates that the field is to be used as a secondary key (an "index" in database terms), allowing the record to be looked up also by this value, in addition to its $puid mentioned elsewhere. This is useful in cases where you have other means of identifying the visitor than just a mobile phone. For instance, when using an RFID tag, you'll want the ID number of the visitor's tag stored in a field marked with an @id() decorator. Note that the values in such fields must be unique in the system for any given record type. Thus, if you re-cycle RFID tags, you must delete (or archive) any previous record using that same RFID number before assigning that RFID number to an @id() field of a new visitor. More on how to delete/archive records below.

Data Record Storage

In addition to being available inside your user script, data records are also stored on disk inside the record directory located in your Blocks root directory. Inside this record directory, Blocks creates one sub-directory per record type, named by the record type ("ExampleRecord" in the example shown above). Inside such a type-specific subdirectory, you'll find one directory per record instance. This is named with Pn where n is the $puid identified discussed above.

Inside that record instance directory, you'll find at least a file named "log.tsv". This is a log file of all data stored or changed in the data record, along with a time stamp for each action. This file uses the popular TSV format (a variant of the more well-known CSV format, but using a tabs as separators rather than commas). For each change applied to the data record, a new line is appended to this file, describing what was changed, when the change was made and what the new value is. This data is used by Blocks to resurrect the data in case you must restart the Blocks server while there are active visitors. It can also be used to analyze visitor behavior, by deriving data such as:

  • Time of arrival.
  • Spots visited, and in what order.
  • How long did the visitor stay at each spot?
  • Name, game scores, or any other data you chose to collect along the way.

You must not modify this data while the visitor is still on site.

Data Record Clean-up

Once a visitor leaves, this data must be discarded to not consume excessive amounts of server memory as new visitors join in. Your user script must manage this clean-up of visitor data records, either one by one (as each visitor leaves or any identifying token is recycled) or en masse once closed for the day (e.g., at 3:00am every day).

This data record clean-up can either simply delete the record(s) or archive them. Use the archive method if you intend to use the data for further analysis of visitor's behaviors. If this is not desired, the data can be completely erased. This latter method also helps alleviate any privacy-related concerns, since no data is being retained. Archived data sets are moved into a subdirectory named "archive" found inside the data set's directory.

To remove individual records, call the $delete function on the record itself. Pass true to the $delete function to archive the record rather than deleting it. To remove all records of a particular type, call the deleteRecords function on the user script itself, passing it the record type and a second optional boolean parameter set to true to archive the records (if desired). See the declarations of these functions in the ScriptBase.ts and Script.ts system_lib files for details.

Other User Script Functions

In addition to declaring the record type, as described above, your user script must contain at least the following functionality:

  • An exported class with the same name as the user script file, extending the Script base class, along with a constructor that calls super with the ScriptEnv passed to the constructor. This is a requirement of all user scripts.
  • A mechanism to clean up data records, as described above. This can be done one by one as visitors leave or tokens are recycled, or en masse once every night. Such a nightly clean-up can be exposed as a public function marked with @callable(), which is then called by a task scheduled to run once every night.

In addition to these mandatory functions, you most likely will have additional functions performing your desired logic as visitors arrive at certain spots, interact with objects, enter data on their mobile phones, etc. The details here depend entirely on your own requirements. An application note will be provided, describing some common scenarios.