Examplary
Start for free
Developer docs

Building apps

Apps connect Examplary to other platforms. A workspace installs an app from its settings, after which the app adds features in the places teachers and students already work: a Send to… option in the export menu, or a secure browser students need to use to take a test.

Our own integrations, like Google Classroom, Woots, Schoolyear and Safe Exam Browser, are built as apps, using the same tools described here.

What an app is made of

An app is a folder with an app.ts file that describes it. In it, you declare:

  • Settings: what a workspace admin, or each teacher, fills in when installing the app, like an API token. See settings.
  • Capabilities: the features the app adds to Examplary, like an export option or an assessment prerequisite.
  • Hooks: the functions behind the settings and capabilities. They run on our servers, in a sandbox, whenever Examplary needs them. See hooks.
  • Components: React components shown in the dashboard, like a "Sign in with…" button in the app's settings. See components.
Loading diagram…

A first app

Start with a new folder, and add the @examplary/apps package and zod (version 4), which describes what a valid setting looks like:

npm install @examplary/apps zod

Then describe the app in app.ts, and default-export it:

app.ts
import { defineApp, InstallationScope } from "@examplary/apps";
import { z } from "zod";
 
import exportOption from "./capabilities/export";
 
const app = defineApp({
  id: "acme.gradebook",
  name: { en: "Acme Gradebook" },
  description: { en: "Send tests to your Acme classes" },
  icon: "./icon.svg",
  scope: InstallationScope.Org,
  public: true,
});
 
app.addSetting({
  key: "apiToken",
  label: { en: "API token" },
  help: { en: "You'll find it in your Acme account settings." },
  type: "password",
  secret: true,
  schema: z.string().min(10),
});
 
app.addCapability(exportOption);
 
export default app;

The id identifies your app on the platform and can't be changed later. Use a reverse domain-like name, in lowercase: <your-org>.<app-name>.

Finally, publish it with the Examplary CLI:

npx @examplary/cli app upload --key YOUR_API_KEY

The app now shows up under Settings → Apps & integrations in your workspace, where an admin can install it.

App properties

PropertyDescription
idUnique ID, like acme.gradebook. Required.
nameDisplay name. Required.
descriptionOne-line description, shown on the app's card. Required.
iconPath to a square icon (SVG or PNG).
readmePath to a Markdown file with a longer description.
previewImagePath to a preview image.
websiteWhere to read more about the app.
versionYour own version number, like 1.2.0.
scopeWho fills in the settings by default: the workspace (org) or each teacher (user). See settings.
publicWhether every Examplary workspace can find and install the app. See publishing.
deprecatedExisting installations keep working, but the app can no longer be installed.

Texts like name and description are translatable: give an object with a value per language ({ en: "…", nl: "…" }). Paths are relative to the app's folder; the CLI uploads the files they point at.

Directory structure

Apart from app.ts, you're free to organize your app however you like. A typical app looks like this:

acme-gradebook/
├── app.ts
├── icon.svg
├── README.md
├── capabilities/
│   └── export.ts
├── components/
│   └── connect-button.tsx
├── lib/
│   └── acme-api.ts
└── package.json

app.ts can import from other files and npm packages, as long as they don't rely on Node.js APIs. See hooks for what's available.