Skip to main content

Embed a Gallery with the SDK

The playbook-sdk is a lightweight, framework-agnostic frontend library that renders a responsive masonry gallery — with search, board navigation, a full-screen viewer, and downloads — backed by your Playbook workspace. It talks to the same REST API documented here, so anything the gallery shows, you can also drive directly over HTTP.

Install​

npm install playbook-sdk

Or drop it in from a CDN:

<script src="https://unpkg.com/playbook-sdk@latest/dist/playbook-sdk.min.js"></script>

Authenticate​

The gallery runs in your visitors' browsers, and anything in a web page can be read by whoever opens it. So the SDK is never given your API token. Your server keeps that token and exchanges it for a short-lived, read-only token limited to the one board the gallery shows; the SDK fetches that from your server.

Add an endpoint to your server that does the exchange. This one is plain Node, with no dependencies:

import { createServer } from "node:http";

const { PLAYBOOK_TOKEN, PLAYBOOK_ORG, PLAYBOOK_BOARD } = process.env;

createServer(async (req, res) => {
if (req.method !== "GET" || req.url !== "/playbook/token") {
res.writeHead(404).end();
return;
}

// If the gallery is not public, check the visitor's session here first.

const upstream = await fetch(
`https://api.playbook.com/v1/${PLAYBOOK_ORG}/access_tokens`,
{
method: "POST",
headers: {
Authorization: `Bearer ${PLAYBOOK_TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ board_token: PLAYBOOK_BOARD, expires_in: 900 }),
},
);
if (!upstream.ok) {
res.writeHead(502).end();
return;
}

const { data } = await upstream.json();
res.writeHead(200, {
"Content-Type": "application/json",
"Cache-Control": "no-store",
});
res.end(JSON.stringify({ token: data.access_token }));
}).listen(3000);

PLAYBOOK_TOKEN is an API token from Developer → SDK, and PLAYBOOK_BOARD is the token of the board to show. The token your endpoint returns can read that board and its sub-boards for up to an hour and nothing else; see Tokens for browser code for exactly what it can do.

Initialize​

Add a container element, then initialize the SDK with your organization slug and a getAccessToken function that calls your endpoint:

<div id="gallery"></div>
import PlaybookSDK from "playbook-sdk";

const getAccessToken = () =>
fetch("/playbook/token")
.then((res) => res.json())
.then((body) => body.token);

const gallery = PlaybookSDK.init({
containerId: "gallery",
organizationSlug: "your-org-slug",
boardId: "your-board-token",
getAccessToken,
});

That's it — a live, searchable gallery renders into #gallery. The SDK calls getAccessToken before its first request and again when the token expires, and keeps the token in memory only. boardId is the board the token was created for, or one of its sub-boards; browsing and search stay inside it.

getAccessToken needs playbook-sdk 1.1.0 or later. Earlier versions take a static authToken, which puts a long-lived token in the page; it still works, with a console warning, and should be replaced.

Customize​

Toggle features, tune the responsive column layout, and hook into events:

PlaybookSDK.init({
containerId: "gallery",
organizationSlug: "your-org-slug",
getAccessToken, // defined above

// Toggle built-in features
enableSearch: true,
enableBoards: true,
enableModal: true,
enableDownload: true,

// Responsive columns (breakpoint in px → column count)
columnBreakpoints: {
default: 1,
768: 2,
1024: 3,
},

// Events
onAssetClick: (asset) => console.log("Clicked:", asset.title),
onSearch: (query) => console.log("Searching:", query),
onDownload: (asset) => console.log("Downloaded:", asset.token),
});

Control it programmatically​

init returns a handle you can drive from your own UI:

gallery.refresh(); // reload assets
gallery.search("logo"); // run a search
gallery.selectBoardById("brand-assets"); // switch board
const assets = gallery.getAssets(); // current assets

Style it​

The rendered markup uses pb--prefixed classes you can override:

.pb-masonry-item img {
border-radius: 16px !important;
}

.pb-board-btn.active {
background-color: var(--brand-color) !important;
}

Next steps​

  • Get access: create an API token for your organization, and keep it on your server.
  • Go deeper: the SDK is powered by the Playbook REST API — use it directly for server-side or custom workflows.
  • Add AI: connect an assistant to the same workspace via the MCP server.