Sharing and Publishing
Learn how to share assets and boards with external stakeholders and publish boards to the web.
Overview
Playbook offers two main ways to make your content accessible to others:
- Shared Links: Private, trackable links for specific assets or boards
- Published Links: Public web pages showcasing your boards
Prerequisites
- Access Token: OAuth2 token with sharing permissions
- Organization Slug: Your organization identifier
- Asset/Board Tokens: IDs of content you want to share
Sharing Assets
Create temporary shared links for individual assets.
Creating an Asset Shared Link
curl -X POST "https://api.playbook.com/v1/my-org/assets/product-photo/share?access_token=TOKEN"
Response:
{
"data": {
"url": "https://playbook.com/s/abc123/product-photo"
}
}
JavaScript Example
async function shareAsset(assetToken) {
const response = await fetch(
`https://api.playbook.com/v1/${ORG_SLUG}/assets/${assetToken}/share?access_token=${ACCESS_TOKEN}`,
{ method: 'POST' }
);
const { data } = await response.json();
return data.url;
}
// Usage
const shareUrl = await shareAsset('product-photo');
console.log('Share link:', shareUrl);
Sharing Boards
Create shared links for entire boards, allowing external viewers to see all assets within.
Creating a Board Shared Link
curl -X POST "https://api.playbook.com/v1/my-org/boards/main-collection/share?access_token=TOKEN"
Response:
{
"data": {
"url": "https://playbook.com/s/def456/main-collection"
}
}
Board Sharing Features
Shared board links include:
- All assets in the board
- Nested subboards (if applicable)
- Asset metadata (title, description, tags)
- Comments (optionally)
- Download capabilities (based on permissions)
Publishing Boards
Publish boards as public web galleries accessible to anyone with the link.
Creating a Published Board
curl -X POST "https://api.playbook.com/v1/my-org/boards/portfolio/publish?access_token=TOKEN"
Response:
{
"data": {
"url": "https://playbook.com/p/my-org/portfolio"
}
}
Published vs. Shared
| Feature | Shared Link | Published Link |
|---|---|---|
| Visibility | Private (requires link) | Public (indexable) |
| Revocable | Yes | Yes (can unpublish) |
| Password Protection | Yes (via UI) | No |
| Analytics | Detailed | Basic |
| SEO | No | Yes |
| Best For | Client reviews, approvals | Portfolios, galleries |
Use Cases
1. Client Review Process
Share assets with clients for feedback:
async function sendForReview(assetTokens, clientEmail) {
// Create shared links for each asset
const sharedLinks = await Promise.all(
assetTokens.map(token => shareAsset(token))
);
// Send email with links
await emailService.send({
to: clientEmail,
subject: 'Assets for Review',
body: `
Please review the following assets:
${sharedLinks.map((url, i) => `Asset ${i + 1}: ${url}`).join('\n')}
Reply with your feedback.
`
});
return sharedLinks;
}
// Usage
await sendForReview(
['design-v1', 'design-v2', 'design-v3'],
'[email protected]'
);
2. Portfolio Website
Embed published boards in your website:
<!-- Embed published board -->
<iframe
src="https://playbook.com/p/my-org/portfolio"
width="100%"
height="800px"
frameborder="0"
allowfullscreen
>
</iframe>
3. Temporary Access for Vendors
Share boards with vendors for a limited time:
async function grantVendorAccess(boardToken, vendorEmail, expiryDays = 7) {
// Create shared link
const { url } = await shareBo ard(boardToken);
// Send with expiry notice
await emailService.send({
to: vendorEmail,
subject: 'Asset Access Granted',
body: `
You have access to our assets for the next ${expiryDays} days:
${url}
This link will be revoked after ${expiryDays} days.
`
});
// Schedule revocation (implement based on your system)
await scheduleRevocation(url, expiryDays);
return url;
}
4. Social Media Sharing
Share individual assets on social platforms:
async function shareToSocialMedia(assetToken, platform) {
const shareUrl = await shareAsset(assetToken);
const asset = await getAsset(assetToken);
const shareText = encodeURIComponent(
`Check out ${asset.title}: ${shareUrl}`
);
const socialUrls = {
twitter: `https://twitter.com/intent/tweet?text=${shareText}`,
facebook: `https://www.facebook.com/sharer/sharer.php?u=${shareUrl}`,
linkedin: `https://www.linkedin.com/sharing/share-offsite/?url=${shareUrl}`
};
return socialUrls[platform];
}
Downloading Shared Assets
Shared links can include download capabilities. Get download URLs for shared assets:
For Shared Assets
curl "https://api.playbook.com/v1/shared/my-org/assets/product-photo/download?sharedlinkslug=abc123&access_token=TOKEN"
Response:
{
"data": {
"display_url": "https://cdn.playbook.com/product-photo.jpg",
"raw_url": "https://cdn.playbook.com/product-photo-original.jpg",
"size": 2456789
}
}
JavaScript Example
async function downloadSharedAsset(sharedOrgSlug, assetToken, sharedLinkSlug) {
const response = await fetch(
`https://api.playbook.com/v1/shared/${sharedOrgSlug}/assets/${assetToken}/download`,
{
headers: {
'sharedlinkslug': sharedLinkSlug
}
}
);
const { data } = await response.json();
return data.raw_url;
}
Managing Shared Links
Tracking Shared Link Usage
Implement your own tracking system:
class SharedLinkTracker {
constructor() {
this.links = new Map();
}
async createTrackedLink(assetOrBoardToken, type = 'asset') {
// Create the share link
const url = type === 'asset'
? await shareAsset(assetOrBoardToken)
: await shareBoard(assetOrBoardToken);
// Store with metadata
this.links.set(url, {
token: assetOrBoardToken,
type,
createdAt: new Date(),
views: 0,
lastAccessed: null
});
return url;
}
trackAccess(url) {
const link = this.links.get(url);
if (link) {
link.views++;
link.lastAccessed = new Date();
}
}
getAnalytics(url) {
return this.links.get(url);
}
listActiveLinks() {
const now = Date.now();
const dayAgo = now - (24 * 60 * 60 * 1000);
return Array.from(this.links.entries())
.filter(([_, link]) => link.lastAccessed > dayAgo)
.map(([url, link]) => ({ url, ...link }));
}
}
Revoking Access
While there's no direct API to revoke shared links, you can:
- Delete the shared asset/board
- Move asset to different board
- Track and warn about expired links
async function revokeSharedAccess(assetToken) {
// Option 1: Move to private board
await updateAsset(assetToken, {
collection_token: 'private-board'
});
// Option 2: Archive the asset
await updateAsset(assetToken, {
tags: [...asset.tags, 'archived']
});
console.log(`Access revoked for ${assetToken}`);
}
Best Practices
1. Descriptive Sharing
Include context when sharing:
async function shareWithContext(assetToken, recipient, message) {
const asset = await getAsset(assetToken);
const shareUrl = await shareAsset(assetToken);
await emailService.send({
to: recipient,
subject: `Shared Asset: ${asset.title}`,
body: `
${message}
Asset: ${asset.title}
Link: ${shareUrl}
Created: ${asset.created_at}
Tags: ${asset.tags.join(', ')}
This link will remain active until revoked.
`
});
}
2. Organize Published Content
Use consistent naming for published boards:
const publishedBoards = {
portfolio: 'main-portfolio',
client_work: 'client-showcase',
team: 'team-photos'
};
async function publishAll() {
for (const [name, token] of Object.entries(publishedBoards)) {
const { url } = await publishBoard(token);
console.log(`Published ${name}: ${url}`);
}
}
3. Watermark Shared Assets
Add watermarks to shared assets (implementation depends on your system):
async function shareWithWatermark(assetToken) {
// Get original asset
const asset = await getAsset(assetToken);
// Download and watermark
const watermarked = await addWatermark(asset.display_url, {
text: 'CONFIDENTIAL',
opacity: 0.3
});
// Upload watermarked version
const watermarkedAsset = await uploadAsset(watermarked);
// Share the watermarked version
return await shareAsset(watermarkedAsset.token);
}
4. Analytics and Monitoring
Track sharing activity:
class SharingAnalytics {
async logShare(type, token, recipient) {
await analytics.track({
event: 'asset_shared',
properties: {
type,
token,
recipient,
timestamp: new Date()
}
});
}
async getMostShared(days = 30) {
const since = new Date(Date.now() - days * 24 * 60 * 60 * 1000);
return await analytics.query({
event: 'asset_shared',
since,
groupBy: 'token',
orderBy: 'count',
limit: 10
});
}
}
Complete Sharing Workflow
Here's a complete implementation with email and tracking:
class PlaybookSharingManager {
constructor(orgSlug, accessToken) {
this.orgSlug = orgSlug;
this.accessToken = accessToken;
this.baseUrl = 'https://api.playbook.com/v1';
}
async shareAsset(assetToken, options = {}) {
const response = await fetch(
`${this.baseUrl}/${this.orgSlug}/assets/${assetToken}/share?access_token=${this.accessToken}`,
{ method: 'POST' }
);
const { data } = await response.json();
// Track the share
if (options.trackingId) {
await this.logShare('asset', assetToken, options.trackingId);
}
return data.url;
}
async shareBoard(boardToken, options = {}) {
const response = await fetch(
`${this.baseUrl}/${this.orgSlug}/boards/${boardToken}/share?access_token=${this.accessToken}`,
{ method: 'POST' }
);
const { data } = await response.json();
if (options.trackingId) {
await this.logShare('board', boardToken, options.trackingId);
}
return data.url;
}
async publishBoard(boardToken) {
const response = await fetch(
`${this.baseUrl}/${this.orgSlug}/boards/${boardToken}/publish?access_token=${this.accessToken}`,
{ method: 'POST' }
);
return await response.json();
}
async shareWithEmail(type, token, recipients, message) {
// Create share link
const url = type === 'asset'
? await this.shareAsset(token, { trackingId: recipients.join(',') })
: await this.shareBoard(token, { trackingId: recipients.join(',') });
// Get asset/board info
const info = await this.getInfo(type, token);
// Send emails
for (const recipient of recipients) {
await this.sendShareEmail(recipient, url, info, message);
}
return url;
}
async getInfo(type, token) {
const endpoint = type === 'asset' ? 'assets' : 'boards';
const response = await fetch(
`${this.baseUrl}/${this.orgSlug}/${endpoint}/${token}?access_token=${this.accessToken}`
);
const { data } = await response.json();
return data;
}
async sendShareEmail(recipient, url, info, message) {
// Implement email sending
console.log(`Sending to ${recipient}:`, {
url,
title: info.title,
message
});
}
async logShare(type, token, trackingId) {
// Log to your analytics system
console.log('Share logged:', { type, token, trackingId });
}
}
// Usage
const manager = new PlaybookSharingManager('my-org', 'your_token');
// Share asset with email
await manager.shareWithEmail(
'asset',
'product-photo',
['[email protected]', '[email protected]'],
'Please review this product photo and provide feedback.'
);
// Publish board
const published = await manager.publishBoard('portfolio');
console.log('Portfolio published at:', published.data.url);
Related API Endpoints
Next Steps
- Learn about Asset Management to organize shared content
- Explore Webhooks to track sharing events
- Read about Comments for collaboration on shared assets