Extensions SDK
Build custom views that run inside a Conexus X module — the way a monday.com module view works. A view is a web page you host; Conexus X frames it in an iframe and talks to it over a single postMessage channel.
Why an iframe
A custom view is code you did not write. Rendered directly into the module DOM it would share globals, styles, and the signed-in user’s JWT. On its own origin it can read none of that — every piece of data it gets, it gets because the host handed it over.
Two independent gates stand between a view and customer data:
- Scopes — the view’s manifest declares what it needs, an admin approves a subset, the host serves only the intersection.
- The route allowlist — a fixed table of endpoints a view may reach at all.
/api-key,/auth/*,/agent/*,/conversations/*and similar are not on it, whatever a view was granted. See Scopes & routes.
Underneath both, the host proxies every call with the signed-in user’s own credentials, so the API re-checks workspace membership and module access exactly as it would in the browser. A scope narrows what a view can ask for; it never widens what the person looking at it may do.
Entry points
| Package | For | Needs React |
|---|---|---|
@conexus-x/sdk | The view, any framework or none | No |
@conexus-x/sdk/react | The view, with hooks | Yes |
@conexus-x/sdk/host | The Conexus X app side, framework-free | No |
@conexus-x/sdk/react-host | The Conexus X app side, as a hook | Yes |
@conexus-x/sdk/manifest | The review pipeline — validate a submission | No |
Quick start
The fastest path is the CLI — see CLI & templates. The view itself looks like this:
import {
useConnection, useViewContext, useScope, useRecords, useCommands, useAutoResize
} from "@conexus-x/sdk/react";
export default function View() {
const { status } = useConnection();
const context = useViewContext();
const canWrite = useScope("records:write");
const commands = useCommands();
// Refetches on its own when the module changes — no socket, no polling
const { data: records, loading } = useRecords(context?.collectionId);
useAutoResize();
if (status !== "ready") return <Spinner />;
return records?.map((record) => (
<Row key={record._id} record={record} canWrite={canWrite}
onOpen={() => commands.openRecord(record._id)} />
));
}Where this sits in the bigger plan
Built today: the protocol, the guest client and host bridge, React bindings for both halves, the scope model and route allowlist, the manifest format and its validator, and two starters (conexus-x-np for Next.js, conexus-x-rp for React + Vite) to scaffold from.
Not built yet, each its own piece of work: backend models/routes for apps, versions, installs and grants; a sandbox test workspace; an automated test-case runner gating submission; an admin approval queue; mounting a view inside the module page itself (today that route is one module with no view switcher); a marketplace, billing and versioned rollout.