Developing with Exhibitera

While Exhibitera Apps includes a robust suite of tools out of the box, the Core API allows you to build completely custom interactives that seamlessly integrate with Exhibitera Hub.


Core Concepts

The Client-Server Architecture

Exhibitera operates on a continuous heartbeat model. Custom interactives (whether they are web-based or compiled native applications) act as clients that "ping" Exhibitera Hub every few seconds. This ping achieves three things:

  1. Presence: It lets Hub know the interactive is online and running.
  2. Analytics: It communicates whether a visitor is currently engaging with the application.
  3. Command Routing: The response from Hub contains any pending commands (like refreshing the page or shutting down the PC).

Browser Apps

The easiest way to create a custom experience for Exhibitera is to create it using browser technologies and load it using Exhibitera Apps' Custom App option. This will automatically provide integration with Exhibtiera, including realtime communicaiton with Hub.

To enable deeper integration and more functionality, you can utilize the Exhibitera Core API JavaScript Library. This library is an ES6 module that abstracts the Core API.

Library Reference
Function Description
getDefinitionProperties() Returns an object containing the user-provided key-value pairs contained in the definition. Use this to change app behavior (like colors, difficulty, or content) without editing the code.
setInteraction(bool) Notifies Hub of visitor activity. Call this with true when a user starts using the exhibit and false when it returns to an attractor state.
async writeRawText(name, text, mode, local) Saves text to a file.
  • name: The filename (no extension).
  • text: The string to save.
  • mode: 'a' for append (default) or 'w' for overwrite.
  • local: If true (default), saves only to the local PC. If false, data is sent to Hub for centralized storage. Using Hub enables you to aggregate data from multiple app instances.
async getRawText(name, local) Retrieve the contents of a previously saved text file. Returns an empty string if the file is not found.
Usage Example

To use the library, ensure your script is loaded as a module in your HTML file:

<script type="module" src="app.js"></script>

Then, in your app.js, import the library and utilize the helper functions:

import * as exAPI from './exhibitera_core_api.js';

// 1. Fetch user-defined settings from Hub
const settings = exAPI.getDefinitionProperties();
const themeColor = settings.color || 'blue';

// 2. Report activity for analytics
document.getElementById('start-btn').addEventListener('click', () => {
  exAPI.setInteraction(true);
});

// 3. Save visitor feedback to Hub (mode 'a' for append)
async function saveFeedback(msg) {
  exAPI.writeRawText('feedback_log', msg, 'a', false);
}

// 4. Retrieve and display data
async function displayStats() {
  const data = await exAPI.getRawText('feedback_log', false);
  console.log('Current Logs:', data);
}

Core API Reference

If you are building a non-browser app (e.g., packaging a Python UI with PyInstaller or using another framework), you will interact directly with the Core API endpoints.

Your app will need to be able to store the URL that Hub is using, which will have the form http://[IP address]:[port]. The Core API endpoints are accessed using the /core prefix. An example of a full API URL is:

http://192.168.1.31:8000/core/checkConnection

The available endpoints are:

GET

/checkConnection

Confirm that the connection to Hub is active and retrieve the supported API levels. /core is always a supported API and may not be listed.

Response
{
  "success": true,
  "supported_apis": ["/v6"],
  "supported_api_levels": [6]
}
POST

/ping

The heartbeat endpoint. Send a JSON object to this endpoint every 5 seconds to update Hub and receive pending commands.

Request Body (JSON)
  • uuid (String, Required): A persistent UUID4 string. This must remain identical across app reboots so Hub recognizes the physical installation.
  • current_interaction (Boolean, Optional): Pass true if a visitor is actively touching or using the exhibit, false if it is in an attractor state.
{
  "uuid": "9e325f88-2f21-4a64-b9ef-f39d549f140f",
  "current_interaction": true
}
Response

Hub will return the current definition as a dictionary and an array of string commands (e.g., "restart", "shutdown") that your app should execute.

{
  "success": true,
  "definition": { ... },
  "commands": ["restart"]
}
POST

/data/{name}/rawText

Write raw text data (such as JSON strings, CSV lines, or vote counts) to the local disk. A .txt extension is automatically appended to the filename.

Path Parameters
  • name (String): A safe filename without an extension.
Request Body (JSON)
  • text (String, Required): The raw string payload to write. If writing JSON, you must serialize it first.
  • mode (String, Default: 'a'): Pass 'a' to append to the file or 'w' to overwrite.
{
  "text": "User selected option B",
  "mode": "a"
}
GET

/data/{name}/rawText

Retrieve a previously written data file from the disk.

Path Parameters
  • name (String): The filename without an extension.
Response
{
  "success": true,
  "reason": "",
  "text": "User selected option B\nUser selected option A\n"
}