Skip to main content

Developing Custom Appspace Cards

  • May 14, 2026
  • 0 replies
  • 10 views

Nurul Ghafar

A developer guide to the Appspace card framework — covering card anatomy, the playback contexts, the Card API, and the supported schema input types used to build custom card templates.

In this article

 


 

Introduction

 

Cards are a type of HTML content that a user can create in the Appspace console and then publish to their channels. They present a simple and fast way to create good-looking content that does not require extensive design experience. Users can pick from a list of predefined themes and then customise the content with their own text, images, or video.

In Appspace there are a few different types of cards:

  • Messaging cards: This is the most common type of card used in Appspace. Messaging cards give the user multiple themes to choose from to fit any type of message. Users can simply use a text field to handle a message from the CEO, or incorporate images and animations to create “Congratulations” or “Happy Birthday” announcements. Appspace provides the Announcement card for this purpose.
  • Service cards: These are cards that have a specific functional purpose. The Room Schedule and Schedule Board cards are great examples of this card type. This card displays room information from an external provider (e.g. Google Calendar), and provides options on how the information is displayed.
  • Feed cards: This type of card gets its content from an external source. Social media, weather, traffic, and RSS cards fall into this category. And just like the service cards, the author can decide how the content is displayed.

 


 

Why Use Cards

 

Cards help to simplify content creation and ensure brand consistency. By using cards, anyone is able to create good-looking content easily. The following are key reasons for using cards.

  • Brand consistency: Brand owners can create base card themes and make those available to users in their organisation. With these themes, users can create their own cards by simply adding text or images in the fields provided for them. This helps to preserve branding, and helps users simply focus on creating a message with the card and publishing it to a channel.
  • Responsive design: Cards are designed to be responsive. This means that a card can automatically adapt itself to different resolutions and orientations while preserving the message created by the user.
  • Integration with external systems: Cards can also be used to integrate with external systems, allowing partners to provide value by building and owning the integrations their clients require. A good example of this is the Seenspire social media card. This card is created and maintained by Seenspire, and it allows customers to display Facebook, Twitter, or Instagram feeds in their Appspace channels.

 

Business Problem

 

Appspace provides a collection of cards that are easy to use, but there is also a need to create custom cards with functionality for unique situations. The question that gets frequently asked by some advanced customers and developers is, “How can I develop my own custom card?”

To date, the information about developing custom cards has been extremely limited, and the details surrounding the Card API have not been readily available.


 

Requirements

 

Knowledge of HTML, JavaScript, or AngularJS is required to develop custom Appspace cards:

  • Developers are free to use any JavaScript development toolkit of their choice.
  • For developers who are familiar with AngularJS, we recommend using our scaffolding project. Details for setting up the scaffolding project are available at the end of this guide. 

 

Solution Overview

 

The goal of this guide is to provide the necessary details for developers to understand the anatomy of a card, along with a base framework for developers to create a custom card.


 

Card Playback Context

 

The behaviour of a card is defined by its playback context. There are a total of six contexts, as listed below:

  • Editing
  • Screenshot
  • Device
  • Theme editing
  • Theme screenshot
  • None

A card can only be loaded with a single context at a time. Depending on the playback context that is loaded, the behaviour of the card will follow its current context appropriately.

Editing context

The Editing context is used during initial card creation or when editing a card configuration in the Appspace console. In this mode the Appspace console editor pushes model updates to the card.

Screenshot context

The Screenshot context is set by the Appspace screenshot service. It is used to allow card developers to modify how they want their card to look when a screenshot is taken for a thumbnail or static image.

Device context

The Device context is used when the card is running on a device. In this mode, the Appspace App renders the card, which needs to communicate with the App. The card needs to listen to the events to know when to start and end its playback, as well as provide feedback to the App when the card is ready to play, completed playback, or throws an error.

Events

These events are triggered by the Appspace App:

  • play — if the card has any transitions or animations they should only start once it gets this event from the App running on the device.
  • pause — this should stop all transitions/animations.
  • api.init — this event is fired when the configuration is fully loaded into the card.

Methods

These methods are used by the developer:

  • NotifyOnLoad — notifies the App that the card is loaded and ready to play.
  • NotifyOnComplete — notifies the App that the card has completed its playback.
  • NotifyOnError — notifies the App that the card has encountered an error while loading.

Theme editing context

The Theme editing context is used when a user creates a new theme or edits an existing theme. This allows the developer to have edit options that are only available during theme editing.

Theme screenshot context

The Theme screenshot context is set by the Appspace screenshot service. It is used to allow card developers to modify how they want their theme to look when a screenshot is taken for a thumbnail or static image.

None

This context is used when the card is embedded in a website. In this context, the card should just autoplay since it will not get any events from the App. The model.json is loaded from the Appspace Console.


 

Building the Card

 

To build a card, a developer will first need to create a card template using a development toolkit of their choice. A card template must have a base theme, but it can also be packaged with additional themes. A theme is just a set of values that determine the presentation of the card. It can have certain card features enabled or disabled, depending on how much control the end user needs to have.

How templates work

  • A brand owner can lock the theme of a template to a specific font style and colour scheme, and allow other users to change the text. In this way, the user can customise the card with their own message but still remain on brand for the look and feel.
  • Users who are content authors will be able to see available card themes in the library. They will then be able to create a card based on any of the available themes.

Once a card is created, it becomes a content item that can be published to channels and devices. A card is essentially a standalone instance of a card template that is based on one of the available themes. Once created, it can be fully customised by the author for display in the Appspace App.

Note: Appspace provides a template tester that developers can use to test and review their card prototype. Details for using the template tester are available towards the end of this guide.


 

Card Template Anatomy

 

A card template must be packaged as a ZIP file and must contain the following files:

  • \manifest.json — contains information about the card package and what’s needed to be able to install the card in the Appspace console.
  • \model.json — this is the default model for the card.
  • \schema.json — defines the form used to get card inputs.
  • \index.html — this is the startup file that is launched in a browser.
  • \thumbnail.svg — this is the icon for the card template (it can also be a JPEG or PNG).

A card template can have additional assets such as fonts, CSS, or JS files from the developer which need to be packaged into a separate folder at the root of the ZIP file:

  • \assets — this is an optional folder that can contain additional fonts, CSS, or JS files.

manifest.json

The manifest is a JSON file that contains information about the card packaged in the ZIP. It uses the following structure:

{
"Name": "Card Name", // The name of the Card template
"Id": "com.dev.cardname", // The developer provided unique id for the card
"Developer": "Company", // The card developer name
"Description": "Description goes here", // Optional set of text describing the card
"Thumbnail": "thumbnail.svg", // A relative path to the image used as a thumbnail
"Schema": "schema.json", // A relative path to the card schema
"Model": "model.json", // A relative path to the card model
"Startup": "index.html", // A relative path to the index page of the card
"Version": "x.x.x", // Version number for the card
"DisplayFormats": [ // Optional list of supported display formats
{ "Type": "tv" },
{ "Type": "mobile" }
],
"NaturalDuration": true, // If the card has a natural duration and can fire
// on complete. Default is false.
"Network": {
"RequiresConnection": true // The card will be streamed from Appspace server
// if set to true
}
}

model.json

The model contains the configuration for a card and is validated against the schema for correctness. The model is a JSON file with the following sample structure:

{
"inputs": [
{ "name": "headline", "value": "Hi Im A Card" },
{ "name": "biline", "value": "Hi Im A bi-line" },
{ "name": "layout", "value": "ior" },
{ "name": "textcolor", "value": "#ff0000" },
{ "name": "background", "color": "#ff0000", "image": "/content/bg.jpg" },
{ "name": "bannerimage", "files": ["/content/banner.jpg"] }
]
}

schema.json

The schema describes the structure of the model and is used by the platform to generate an appropriate UI for a user to populate the model during creation. For more information on the supported types, see Supported Input Types.

The schema is a JSON file with the following structure:

{
"inputs": [ // Collection of inputs contained in the model
{
"name": "property", // Name of the input property
"locked": false, // When true the input is not displayed in the card form.
// Can be updated during theme creation to hide or show
// the input based on theme.
"label": "My Property", // Label to use to display in the form
"type": "input_type", // Type of property object (see Card input type dictionary)
"validation": { // Optional validation rules for the input type
"minlength": 0,
"maxlength": 255,
"required": true
}
}
]
}

Schema example:

{
"version": "1.1",
"settings": { "fontfamily": ["Arial"] },
"inputs": [
{
"name": "headline",
"label": "Headline",
"placeholder": "Headline",
"type": "richtext",
"value": "",
"options": {
"style": {
"font": true,
"color": true,
"size": ["50%","75%","100%","125%","150%","175%","200%","250%","300%"],
"alignment": true,
"backgroundcolor": true,
"containercolor": false,
"decorations": true
}
},
"validation": { "required": false }
}
]
}

Full screen card schema

Some cards have just a couple of options and don’t require a form. Or some developers may wish to show the card in full screen during editing mode and overlay the options. A good example of this is the Google Traffic card. In these situations, the form is not visible and the developer will need to use CustomData to update the model.

Example of schema for a full-screen card:

//..................
"version": "1.1",
"editor": {
"form": { "visible": false },
"preview": {
"background": {
"background-color": "rgb(250,250,250)",
"background-image": "none"
},
"scale": "auto"
}
},
//..................

 

Card API

 

The Card API is a JS module that must be included in the startup index.html file of the card template. It provides a set of methods and events to facilitate communication between the host and the card.

Methods for developers

Method Notes Return
subscribeModelUpdate(callback) Subscribes to model update events by providing a callback. Developers should wait for this event before loading their card logic. none
subcribeToMessages(callback) Subscribes to all messages from parent window. Typical messages are “play”, “pause”, “api.init”. If there are animations, the template should wait for the “play” message before running. none
getModel() Returns the Card model along with the card’s custom data object
getConfig() Returns the config object associated with the template. The config includes player properties that are passed at runtime. object
isEditing() [Deprecated] Returns true or false depending on whether the card is being edited. Use getPlaybackContext() instead. boolean
getPlaybackContext() Returns the playback context string
getModelProperty(propertyName) Returns the model value for a property by name object
notifyOnLoad() Raises an event to the host that the Card has loaded. This will trigger the device to display the card. none
notifyOnComplete() Raises an event to the host that the Card has completed none
notifyOnError() Raises an event to the host that there was a problem loading or displaying the card none
api.updateModelCustomData(object) During editing context, the template can pass a custom data object to be saved in the model for use during playback. If you call this to update the custom data, please note that the entire object will be replaced. none
api.updateModelInput(input) Update model input none
api.xhr(URL, settings) Accepts a jQuery-like config object and performs an XHR request at the app level promise
postMessage(Message Object) Post the message to the App window none

 

Supported Input Types

 

When building cards, there are a collection of supported input types that can be included in the schema. These input types are essentially UI controls that the user interacts with to provide content or data into a card. There are currently a total of fifteen input types, and the collection will continue to grow as new input types are created in the future.

Summary of input types:

Input type Description
fileupload Upload files
fontupload Upload custom fonts
richtext Richtext formatting control
textbox Single line text entry
textarea Larger text block entry
textstyle Define text format style
tagsinput Tag input field
background Background color or image
checkbox Checkbox item list
radio Radio option list
dropdown Single select dropdown list
multiselect Multiselect dropdown list
colorpicker Color picker tool
codeview HTML snippet entry
celldata Tabular data entry

 

Input type: fileupload

This input type is used to upload files to the card; most commonly used to add media files (images or videos) from the library or a user’s computer so they can be used as content inside the card.

Schema and model example:

{
"name": "bannerimage",
"label": "Banner Image",
"type": "fileupload",
"options": {
"maxfiles": 5,
"sortEnabled": true,
"toolbarButtons": [
{ "label": "Crop", "extensions": [".bmp", ".jpeg", ".wmv"] },
{ "label": "Edit <span class=\"glyphicon glyphicon-pencil\"></span>", "extensions": null }
]
},
"validation": {
"fileextensions": [".bmp", ".jpg", ".png"],
"required": false
}
}

 

Input type: fontupload

This allows the user to upload custom fonts to the card. The fonts will become available for use in the text fields. The Card API will auto download and install the fonts into the browser when loading the card.

Schema and model example:

{
"name": "fontuploader",
"label": "Upload Custom Font",
"type": "fontupload",
"options": {},
"validation": { "required": false }
}

 

Input type: richtext

This input type is used when a user needs to have all the formatting options available in a text field. This is used mainly if a user would need to have text with multiple font styles in a single field.

Schema and model example:

{
"name": "richtext",
"label": "Rich Text",
"placeholder": "Enter your text",
"type": "richtext",
"options": {
"sticky": true,
"style": {
"font": true,
"color": true,
"size": ["200%","150%","125%","100%","75%","50%","25%"],
"alignment": true,
"backgroundcolor": true,
"decorations": true,
"list": true,
"indent": true,
"insertLink": true
}
},
"validation": { "minlength": 2, "maxlength": 10, "required": true }
}

 

Input type: textbox

This input type allows the user to enter a line of text. This is generally used for titles or headlines where the text format is the same. Under the options in the schema you can optionally set the type as well to number or password to change the behaviour of the input field.

Schema and model example:

{
"name": "headline",
"label": "Headline",
"placeholder": "Sample card",
"type": "textbox",
"options": {
"tooltip": "Enter title",
"type": "password",
"style": {
"locked": false,
"color": true,
"size": ["200%","150%","125%","100%","75%","50%","25%"],
"alignment": true,
"backgroundcolor": true,
"gridcolor": true,
"decorations": true
}
},
"validation": { "required": false, "minlength": 3, "maxlength": 50 },
"locked": false
}

 

Input type: textarea

This input is similar to the textbox, but it displays multiple lines of text which is generally used when users need to enter more text than just a headline or title. Just like the text box, this input field has a single formatting style for the entire text entered.

Schema and model example:

{
"name": "biline",
"label": "Bi-line",
"placeholder": "Enter your bi-line",
"type": "textarea",
"rows": 10,
"options": {
"style": {
"locked": false,
"font": true,
"color": true,
"size": ["200%","150%","125%","100%","75%","50%","25%"],
"alignment": true,
"backgroundcolor": true,
"decorations": true
}
},
"validation": { "minlength": 0, "maxlength": 100, "required": true }
}

 

Input type: textstyle

This input type is used to define the formatting of text that the user cannot change. An example of this would be the date and/or time that is displayed in the card.

Schema and model example:

{
"type": "textstyle",
"name": "textstyle",
"label": "Text Style",
"options": {
"style": {
"font": true,
"color": true,
"size": ["200%","150%","125%","100%","75%","50%","25%"],
"alignment": true,
"backgroundcolor": true,
"gridcolor": true,
"decorations": true
}
}
}

 

Input type: tagsinput

This allows the user to enter a number of tags that can then be referenced inside the card.

Schema and model example:

{
"name": "tagsInput1",
"label": "Tags",
"type": "tagsinput",
"placeholder": "Enter your tag",
"template": "user",
"displayProperty": "Name",
"autocompleteSettings": {
"data": [
{ "Name": "John Smith", "Type": "user" },
{ "Name": "Jane Boyd", "Type": "user" },
{ "Name": "Marketing", "Type": "usergroup" }
],
"addFromAutocompleteOnly": false
},
"options": {},
"validation": { "required": false }
}

 

Input type: background

This component allows the user to set up the background of the card. The user can have an image (or multiple images) or set a background colour. Alternatively a user can do both if the image is a PNG that has transparency.

Schema and model example:

{
"name": "background",
"label": "Background Color or Image",
"type": "background",
"options": {
"palette": ["#ffffff", "#f00", "#00ff00"],
"defaultcolor": "#000000",
"showcolor": true,
"showimage": true
},
"validation": { "fileextensions": [".mp4"] }
}

 

Input type: checkbox

This component allows the developer to expose various options that the user can enable or disable when they create a card.

Schema and model example:

{
"type": "checkbox",
"name": "cb",
"label": "Checkbox",
"validation": { "required": false, "minitems": 2, "maxitems": 3 },
"options": {},
"items": [
{ "value": "1", "label": "Show Legend", "checked": true },
{ "value": "2", "label": "Show Table", "checked": false },
{ "value": "3", "label": "Show as Donut Chart","checked": false },
{ "value": "4", "label": "Show as Bar Chart", "checked": false }
],
"conditions": [
{
"condition": "model.value.length > 0 && model.value.indexOf('1') >= 0",
"actions": ["headline.model.value='Show Legend Condition'"]
},
{
"condition": "model.value.length > 0 && model.value.indexOf('2') >= 0",
"actions": ["biline.schema.visible=false"]
},
{
"condition": "model.value.length > 0 && model.value.indexOf('2') < 0",
"actions": ["biline.schema.visible=true"]
}
]
}

 

Input type: radio

This component allows the user to select one of the multiple options available, which are defined by the developer for the card.

Schema and model example:

{
"type": "radio",
"name": "radio",
"label": "Radio",
"validation": { "required": false },
"options": { "defaultitem": 1 },
"items": [
{ "value": 1, "label": "Show Legend" },
{ "value": 2, "label": "Show Table" },
{ "value": 3, "label": "Show as Donut Chart" }
]
}

 

Input type: dropdown

This component is similar to the radio buttons, as it also allows the end user to select one option from multiple options available. The example below allows the user to select the image placement in the card. The three options are predefined by the developer, but the user can select which one to use.

Schema and model example:

{
"name": "layout",
"label": "Layout",
"type": "dropdown",
"options": { "defaultitem": "ior" },
"items": [
{ "icon": "", "label": "Image on Left", "value": "iol" },
{ "icon": "<img src='http://icons.iconarchive.com/icons/yellowicon/game-stars/256/Mario-icon.png'>", "label": "Image in Middle", "value": "iim" },
{ "icon": "<i class='fa fa-film'></i>", "label": "Image on Right", "value": "ior" }
]
}

 

Input type: multiselect

This component allows the developer to expose multiple features and then give the end user the option of which ones they want to enable during card creation.

Schema and model example:

{
"type": "multiselect",
"name": "language",
"label": "Multiselect",
"placeholder": "Select language",
"options": { "maxselection": 2 },
"validation": { "required": true },
"items": [
{ "value": "english", "label": "English", "icon": "<i class='fa fa-film'></i>" },
{ "value": "deutsch", "label": "Deutsch", "icon": "<img src='app/asset/images/calendar.svg'>" },
{ "value": "french", "label": "French", "icon": "<i class='fa fa-desktop'></i>" },
{ "value": "italian", "label": "Italian", "icon": "<i class='fa fa-home'></i>" },
{ "value": "malay", "label": "Malay", "icon": "<i class='fa fa-user'></i>" }
]
}

 

Input type: colorpicker

This component allows the user to specify the colour of an object in the card. This is generally used for non-text objects like the background of a zone, the colour of a header, etc. You also have the ability to customise the CSS for the input by using the form in the schema.

Schema and model example:

{
"name": "textcolor",
"label": "Text Color",
"type": "colorpicker",
"options": {
"defaultcolor": "#ffffff",
"palette": ["#ffffff", "#f00", "#00ff00"],
"allowtransparency": true,
"allowempty": true
},
"form": {
"css": {
"width": "10%",
"display": "inline-block",
"margin-right": "1%",
"padding-bottom": "1em"
}
},
"$$domID": "palette1_20",
"visible": false,
"locked": false
}

 

Input type: codeview

This is an advanced input which allows a user to enter their own HTML snippet into the card. The result can be rendered inside an iframe in the card.

Schema and model example:

{
"name": "codeview",
"label": "Codeview",
"type": "codeview",
"options": {},
"validation": {}
}

 

Input type: celldata

This component allows the user to enter tabular data. The data can then be used to display the data, display select parts of the data, or generate charts and graphs based on the data. The data can be manually entered or the user can upload an .xlsx file.

Modal for data entry: the user enters labels and values into a tabular modal, or drops in an .xlsx file to populate it.

Schema and model example:

{
"name": "doughnutchart",
"label": "Doughnut chart",
"type": "celldata",
"options": {
"tooltip": "",
"columns": [
{ "name": "label", "label": "Label", "type": "text", "format": null, "placeholder": "Enter label" },
{ "name": "value", "label": "Value", "type": "text", "format": null, "placeholder": "Enter value" }
]
}
}

 

Appspace Development Tools

 

Appspace provides two tools to help developers get started with creating cards:

  • The first is an AngularJS scaffolding project.
  • The other tool is an online template tester that developers can use to test their cards.

Appspace cards scaffolding project

The scaffolding project is designed to help developers easily create their cards. All you have to do is place your files in the appropriate folders, and when the template is built, your JS and CSS code will be automatically added to the index.html and minified.

Scaffolding project setup

Download the scaffolding project from the community forum and follow the steps below to get it all set up.

Prerequisites: Node.js and NPM

To build and run the project:

  1. Navigate to the src directory in your terminal window.
  2. Run npm update -g.
  3. Run npm install.
  4. Run npm start or npm run start:ssl.
    • This will automatically start hosting your card at port 8000 on HTTP & HTTPS.
    • To open in the browser or in the Template Tester, use the following URL: http://localhost:8000/ or https://localhost:8000/.

To build the template ZIP file for uploading to the Appspace console:

  1. Navigate to the src directory in your terminal window.
  2. Run npm run-script build.
    • The ZIP file will be created in the project artifacts folder.

Custom data

The scaffolding project expands on the methods you can use when using custom data. The Card API offers the following method to update the custom data object:

  • api.updateModelCustomData(object)
    • This requires that you update the full object each time.

The Card API service includes useful methods to handle custom data easily:

  • cardApiService.appendCustomData({"card.path.to.property": "value", "card.secondproperty": "val"}) will create the custom data object and create both properties in their correct path. Consecutive calls to the method will append and update the custom data object instead of replacing the whole object.
  • cardApiService.readCustomData("card.path.to.property") will get that value for you so you don’t have to worry about handling undefined or non-existent paths.

Components

Everything in the Scaffold card is built as a component, so everything is reusable, and follows the single responsibility principle. The main components of the card are the following:

  • Base View: The root component, and is always included.
  • Editing View: Displayed when the card is in ‘Editing’ or ‘Theme Editing’ context.
  • Screenshot View: Displayed when the card is in ‘Screenshot’ or ‘Theme Screenshot’ context.
  • Playback View: This is where the actual view of the card will reside, and can be included in other views. It will be used as the default view when the device is in ‘Device’ or ‘None’ context.
  • You can change which components appear on which context by editing the Base View component.

Custom components

You can create a folder for a custom view under the components folder. You just need to follow the below structure:

Components\
my_custom_view\
my_custom_view.html
my_custom_view.js
my_custom_view.scss

Template Tester

The Template Tester is an online tool that developers can use to test their cards. All you have to do is enter the URL of your card, and the Template Tester will render the form and card preview, as well as show the schema and model for your card. Making any changes to either will be reflected in the preview.

Template Tester URL: https://developer.appspace.com/tools/card-template-tester/templatetester.html


 

Conclusion

 

The information presented in this guide provides the initial framework for a developer to create a custom Appspace card. With a JavaScript or AngularJS development toolkit of choice, developers can refer to the Card API and the collection of supported input types to start building custom cards.

This topic has been closed for replies.