Polinode
Guide
Home Page
Login
Guide
Home Page
Login
  • Guide

    • Introduction
    • Networks
    • Surveys
    • Passive Data
    • Social Data
    • Research Data
    • Automations
    • Your Account
    • FAQ
    • API
    • Embedding

Embedding

Overview

Embedding lets your application show Polinode networks inside its own pages and drive them from your code: open a saved view, filter, focus a node, read what is on screen and save a view.

Every person who views an embedded network is a real Polinode user that your integration provisions and manages through the API (a managed user). You act as the identity provider for those users only: you authenticate them in your application, and you ask Polinode for a short-lived session for each one.

Embedding is off by default. It is enabled per organization by Polinode (contact support), which also sets the number of managed-user seats. After that, an organization admin configures it under Organization Settings → Embedding:

  • Allowed host origins: the exact origins of the pages that may frame Polinode, such as https://app.example.com or https://app.example.com:8443. Wildcards and paths are not accepted.
  • Embeddable networks: the only networks that can be granted to managed users or opened in an embedded session. By default All owned networks is on: your integration can grant any network owned by a member of your organization. Turn that off to choose specific networks instead.
  • Data disclosure: making a network embeddable authorizes your integration to receive the network's full content, including node and edge attributes and its structure, and to pass it to its own providers, including AI providers.

How it Works

  1. Your backend provisions a managed user and grants it access to one or more embeddable networks.
  2. When that person opens the page in your application, your backend creates a session for them and receives a launch token (valid for 60 seconds, single use).
  3. Your page loads https://app.polinode.com/embed/<sessionId> in an iframe and uses the @polinode/embed SDK. The SDK and the iframe pair over a private MessageChannel, and the SDK hands the iframe a launch token by calling your getLaunchToken callback.
  4. The iframe exchanges the launch token for an access token (valid for 15 minutes) that it keeps in memory. No cookies are used. Before the access token expires, and only if the viewer or your code has been active, the iframe asks the SDK for a new launch token.
  5. Your code drives the viewer through the SDK's commands.

Managed Users

All embedding API calls use an organization API credential that has the Embedding scope. "Full API access" credentials include it; a credential with custom scopes needs it selected when you create the credential. The scope has no effect until embedding is enabled for your organization. Any credential of your organization with this scope can manage all of your organization's managed users.

A managed user:

  • has no password, cannot sign in to Polinode directly, and never receives product emails;
  • has a placeholder email address and is shown by its display name;
  • appears in your organization's user list with an Embedded badge, and uses your managed-user seats rather than your ordinary user seats;
  • has a fixed organization permission (Access-only, Simplified Access-only or Standard User, optionally read-only), set when it is first provisioned;
  • is subject to your organization's AI Networks Chat settings and the per-user AI chat toggles in the user list.

Create or Update a Managed User

PUT /api/v2/embed/users/:externalId

externalId is your own identifier for the person (1–128 characters of letters, digits and . _ : @ | -). The request is idempotent: the first call creates the user and takes a seat; later calls update it.

FieldRequiredDescription
displayNameon createThe name shown in Polinode.
chatAccessnooff, presetOnly (preconfigured questions only) or full. Defaults to full for a new user.
orgPermissionnoAccess-only (default), Simplified Access-only or Standard User. Fixed after creation.
readOnlynotrue for a read-only user (View access only). Fixed after creation.

Returns 201 on create and 200 on update, with the user's externalId, displayName, status, chatAccess, networks and activity dates. Returns 402 with code EMBEDDED_SEAT_LIMIT when all seats are in use, and 409 with code EMBED_MEMBERSHIP_IMMUTABLE if you try to change orgPermission or readOnly.

Calling it for a deactivated user reactivates the user and takes a seat again.

Grant or Remove Network Access

PUT /api/v2/embed/users/:externalId/networks/:networkId with { "permission": "View" | "Edit" }

DELETE /api/v2/embed/users/:externalId/networks/:networkId

The network must be one of your embeddable networks. Edit is needed to save or update views. Removing access takes effect on the viewer's next request.

Deactivate a Managed User

POST /api/v2/embed/users/:externalId/deactivate

Deactivating a user ends all of its sessions, removes all of its network access and frees its seat. Views the user saved remain on their networks. Deactivation is how you offboard a person; a deactivated user can be reactivated later with the same externalId.

List Managed Users

GET /api/v2/embed/users?status=active|deactivated&limit=100&offset=0

Returns { total, offset, limit, users } for reconciliation with your own records. limit is at most 500.

Sessions

Create a Session

POST /api/v2/embed/sessions

FieldRequiredDescription
externalIdyesAn active managed user.
networkIdsyesExactly one network id: an embeddable network the user has access to.
originyesThe origin of the page that will frame the viewer; must exactly match an allowed host origin.
maxMinutesnoSession lifetime, 1–720 minutes (default 60).
uinoOmit it to show everything. Otherwise { menu?, aiChat? } to hide parts of the viewer; see Viewer Options.
headernonone (default) or title: a slim strip showing the network and view names.

Returns 201 with { sessionId, launchToken, launchTokenExpiresAt, expiresAt, ui, header }, where ui is the normalized form of what you sent.

Viewer Options

By default an embedded viewer shows everything: every Explore left-menu item and AI Networks Chat. The optional ui object only hides things, and anything you leave out stays shown:

FieldDescription
menuOmitted: every item is shown. To show only some, list them from layout, open, save, templates, labels, layers, tables, metrics, color, size, filter, shapes, rollup, export and settings. []: no left menu at all, leaving the network, legend and node details, for experiences driven entirely by your code. Items always appear in Explore's own order, whatever order you list them in.
aiChatOmitted or true: AI Networks Chat is shown. false hides both its floating button and its menu item.
{ "menu": ["open", "filter", "color", "size"], "aiChat": false }

An unknown key or menu item, or a value of the wrong type, fails with 400 and code INVALID_ARGS. The viewer's session.info() reports the session's ui.

Hiding items only changes what is on screen. What the viewer can do is still decided by its network access (View or Edit) and its AI chat access, so do not rely on a hidden menu item to restrict a user.

The embedded Explore page has no Back button, since there is no network list inside an embed. With header: 'title', a slim strip above the network shows the network and view names.

Issue a New Launch Token

POST /api/v2/embed/sessions/:sessionId/launch-tokens returns { launchToken }. The SDK asks for one when the viewer loads, reloads or needs to refresh its access token.

Revoke a Session

DELETE /api/v2/embed/sessions/:sessionId

Revoke the session when your user logs out of your application. Simply stopping refreshes is not revocation.

A session also ends when it reaches maxMinutes, after 30 minutes without any viewer or bridge activity, when the managed user is deactivated, when embedding is disabled, or when its origin is removed from the allowed host origins. Disabling embedding or removing an origin also stops the embed page itself from loading in a frame on that origin straight away. After a revocation, new requests fail immediately; signed network data links already issued stay valid for up to 5 minutes, and data already in the browser stays there until you remove the iframe.

Host Responsibilities

  • Launch-token callback. Your getLaunchToken(sessionId) must call your own backend, which must identify the viewer from its own authenticated session and check that this viewer owns sessionId before requesting a launch token. A session id on its own must never yield a launch token.
  • Logout. Revoke the session and remove the iframe when your user logs out.
  • Framing. Use an iframe such as:
<iframe
  src="https://app.polinode.com/embed/SESSION_ID"
  sandbox="allow-scripts allow-same-origin allow-popups allow-popups-to-escape-sandbox"
  referrerpolicy="no-referrer"
  style="border: 0; width: 100%; height: 700px"
></iframe>
  • Identity. You are responsible for how your users authenticate, including whether that meets your organization's SSO or MFA expectations; your organization's MFA requirement does not apply to managed users. Polinode's audit log records the identity your integration asserted, not proof that a particular person acted.
  • Your page. Code running on your page, and privileged browser extensions, can use everything the bridge exposes.

The SDK

import PolinodeEmbed from "@polinode/embed";

const pn = await PolinodeEmbed.create(document.getElementById("polinode"), {
  sessionId,
  getLaunchToken: (id) => fetch(`/my-backend/polinode/launch-token/${id}`).then((r) => r.json()).then((b) => b.launchToken),
});

await pn.views.open(landscapeViewId);
await pn.layers.filter({ attribute: "External intent", min: 0.7 });
await pn.nodes.focus({ label: "Programme Aurora" }, { zoom: 2 });
const [aurora] = await pn.nodes.get([{ label: "Programme Aurora" }]);

pn.on("node.clicked", ({ nodeId }) => console.log("clicked", nodeId));
pn.on("session.expired", () => showSignedOutMessage());

create() resolves once the viewer has loaded the network. Every command returns a promise that resolves only when the change has been applied (including any camera animation), or rejects with a PolinodeEmbedError carrying a code.

Commands

CommandDescription
session.info()Display name, capabilities, network scope, viewer options (ui) and expiry.
state.get(){ networkId, viewId, dirty, layers, selectedNodeIds, visibleNodeCount, revision }.
network.info()Name, node and edge counts, node attribute names and types.
views.list() / views.open(viewId)The network's saved views; open one.
views.save({ name, description? }) / views.update()Save the current state as a new view, or onto the open one. Needs Edit access; saved views are visible to the network's other users.
layers.filter({ attribute, values }) / layers.filter({ attribute, min, max })Filter nodes by a categorical or numeric attribute. Returns { layerId }.
layers.color({ attribute }) / layers.size({ attribute })Color or size nodes by an attribute. Returns { layerId }.
layers.remove(layerId) / layers.clear()Remove one layer, or all of them.
nodes.find({ attribute, equals | contains | min / max, limit?, cursor? })Visible nodes matching a condition, 50 per page by default (at most 200), with coverage and a cursor for the next page.
nodes.get(refs)Look up to 100 nodes; each result reports resolved, ambiguous, fuzzy, hidden or not_found.
nodes.focus(ref, { zoom? }) / nodes.select(refs) / nodes.clearSelection()Select nodes and move the camera.
camera.fit(refs?)Frame the given nodes, or the whole network.
chat.ask(message, { newChat? })Ask AI Networks Chat a question on the viewer's behalf (up to 4,000 characters). The viewer's chat panel opens on the conversation, so the viewer sees what was asked. Resolves as soon as the question is sent; the answer arrives as a chat.reply event. RATE_LIMITED while another question is being answered.
chat.messages()The current conversation: [{ id, role, content, isError }].
chat.open() / chat.close() / chat.new() / chat.cancel()Open or close the chat panel, start a new conversation, or stop the answer in progress.
cancel(requestId)Cancel a queued or running command.

A node reference is { id } or { label }. Commands that change something need a reference that identifies exactly one visible node: an ambiguous or approximate label fails with AMBIGUOUS_NODE and up to 10 candidates, and a missing or filtered-out node fails with NOT_FOUND.

Changes run one at a time, in order, together with the viewer's own clicks. At most 20 can be pending (RATE_LIMITED beyond that), and each has a deadline (30 seconds by default, TIMEOUT after it).

Every reply and event carries a revision that increases whenever what is on screen changes, whether your code or the viewer changed it. Pass { ifRevision } to a command to have it fail with STALE_STATE if the viewer has moved on since you last looked.

Events

ready, busy { on }, state.changed { revision }, selection.changed { selectedNodeIds }, node.clicked { nodeId }, chat.question { messageId, content, source }, chat.reply { messageId, content, isError }, error, session.expired.

chat.question and chat.reply report every question and answer in the viewer's chat, whether your code or the viewer asked it (source is host or viewer); a cancelled answer arrives as chat.reply with cancelled: true. Answers are Markdown.

AI Networks Chat

chat.ask behaves exactly as if the viewer had typed the question: it uses the viewer's chat access (chatAccess), counts against your organization's AI allowance, and is refused with NOT_PERMITTED when the session's ui.aiChat is false or the viewer has no chat. A viewer with chatAccess: 'presetOnly' is offered only the network's preset questions, and chat.ask is held to them too. This shapes what the viewer is offered rather than being a hard content boundary: a viewer who scripts requests with their own session could still steer an answer. Their chat stays confined to the networks you granted and counts against your AI allowance either way, so use off when a viewer must not reach the AI at all. The AI may add layers or open views while answering; those changes raise state.changed like any other.

pn.on("chat.reply", ({ content, isError }) => showAnswerInMyApp(content, isError));
await pn.chat.ask("Which division is most isolated from the others?", { newChat: true });

Error Codes

UNKNOWN_COMMAND, INVALID_ARGS, NOT_PERMITTED, NOT_FOUND, AMBIGUOUS_NODE, STALE_STATE, CANCELLED, TIMEOUT, RATE_LIMITED, SESSION_EXPIRED, INTERNAL.

EmbedView v1

Views are described in a versioned format:

{
  "version": 1,
  "id": "…",
  "name": "Landscape",
  "description": "",
  "layers": [
    { "id": "L1", "operation": "Filter", "appliedTo": "nodes", "attribute": "Region", "attType": "string", "hidden": false, "values": ["EMEA"] },
    { "id": "L2", "operation": "Color", "appliedTo": "nodes", "attribute": "External intent", "attType": "number", "hidden": false, "min": 0, "max": 1 },
    { "id": "L3", "operation": "Calculate", "summary": "Calculate: Betweenness Centrality on nodes", "readOnly": true }
  ],
  "camera": { "x": 0.5, "y": 0.5, "ratio": 1, "angle": 0 },
  "display": { "backgroundColor": "rgba(51, 51, 51, 1)", "showLabels": "always", "showEdges": true }
}

Filter, Color and Size layers on node attributes are described in full. When the left menu is shown, the viewer can add any other kind of layer through the Explore page; those appear as read-only entries with a summary, so your code always sees what is on screen.

Limits

  • Provisioning, grants and session creation: 600 requests per hour per organization.
  • Launch tokens: 6,000 per hour per organization (roughly the number of embedded page loads).
  • Metric calculations in embedded sessions: 3,000 per hour per organization.
  • Launch token redemptions: 60 per hour per session, plus a fixed ceiling per IP address.
  • If your integration needs different organization or per-session limits, contact Polinode support to have them adjusted for your organization.
  • Each session can run one metric calculation and one AI Networks Chat request at a time.
  • AI Networks Chat in embedded sessions uses your organization's AI budget. Requests already in progress count against the budget, so many simultaneous conversations cannot exceed it.

Branding

Embedded viewers have no Polinode navigation bar. A small Polinode icon is shown at the bottom right, beside the AI Networks Chat button (or in its place when chat is hidden). Hovering over it shows "Powered by Polinode", and clicking it opens www.polinode.com in a new tab. White-labelled organizations have no Polinode mark, and their embedded viewers use the organization's own colors.

Node images hosted on any https site are displayed in embedded viewers.

Prev
API