Appearance
Pitcher Apps - Deep Dive
What Are Pitcher Apps?
Pitcher Apps are web-based plugins that extend the platform's functionality. They can be embedded in multiple contexts (called "modules") and interact with the platform via the Pitcher JavaScript SDK.
Related Documentation
- Platform Architecture - Overview of the Pitcher platform architecture
- Complete Architecture - Comprehensive architecture documentation including apps
- Architecture Diagrams - Visual diagrams showing how apps integrate
- App Types - Guide to different app types and modules
- Getting Started - Start building your first app
- app.json Reference - Complete app manifest specification
App Architecture
App Manifest (app.json
)
json
{
"name": "product-configurator",
"display_name": "Product Configurator",
"icon": "assets/icon.png",
"version": "1.2.0",
"description": "Interactive product configuration tool",
"type": "web",
"authors": ["John Doe <john@example.com>"],
"provide": [
"ui",
"multimedia_selector"
],
"require": ["crm"],
"module": {
"ui_app": {
"enabled": true,
"entry": "index.html",
"headless": false,
"auto_install": true,
"defaults": {
"dimensions": {
"width": "100%",
"height": "100vh"
}
}
},
"canvas": {
"enabled": true,
"entry": "canvas.html",
"settings": {
"sections": [
{
"label": "Configuration",
"fields": [
{
"type": "text",
"name": "api_key",
"label": "API Key",
"help_text": "Your product catalog API key",
"is_required": true
},
{
"type": "select",
"name": "catalog",
"label": "Product Catalog",
"options": [
{ "label": "Electronics", "value": "electronics" },
{ "label": "Furniture", "value": "furniture" }
]
},
{
"type": "boolean",
"name": "show_pricing",
"label": "Show Real-time Pricing"
}
]
}
]
},
"defaults": {
"dimensions": {
"width": "800px",
"height": "600px"
},
"settings": {
"catalog": "electronics",
"show_pricing": true
}
},
"shortcuts": {
"fullscreen": [
{
"id": "refresh",
"icon": "refresh",
"tooltip": "Refresh Product Data",
"order_override": 1
}
],
"presentation": [
{
"id": "configure",
"icon": "settings",
"tooltip": "Configure Product"
}
],
"edit": [
{
"id": "preview",
"icon": "eye",
"tooltip": "Preview Configuration"
}
]
}
},
"overlay_app": {
"enabled": true,
"entry": "overlay.html",
"defaults": {
"dimensions": {
"width": "300px",
"height": "400px"
}
},
"app_options": {
"placement": "bottom-right",
"mode_config": {
"fullscreen": { "show": true },
"presentation": { "show": true },
"edit": { "show": false }
}
}
}
}
}
App Module Types
1. UI App (ui_app
)
Full-screen standalone application
Examples:
- Account Browser - Browse and display CRM accounts (you build the UI)
- Meeting Scheduler - Schedule events with calendar integration
- Analytics Dashboard - View content performance metrics
- Content Library - Browse and search all files
- Custom Reports - Build custom reporting dashboards
Code Example:
html
<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
<title>Account Browser</title>
<script src="https://cdn.jsdelivr.net/npm/@pitcher/js-api"></script>
</head>
<body>
<div id="app">
<h1>Account Browser</h1>
<div id="accounts"></div>
</div>
<script>
const api = window.pitcher.useApi();
async function loadAccounts() {
// Query Salesforce accounts using CRM integration
const result = await api.crmQuery({
query: 'SELECT Id, Name FROM Account ORDER BY Name LIMIT 100'
});
renderAccounts(result.records);
}
function renderAccounts(accounts) {
const container = document.getElementById('accounts');
container.innerHTML = accounts.map(account => `
<div class="account-card" onclick="showAccountDetails('${account.Id}', '${account.Name}')">
<h3>${account.Name}</h3>
</div>
`).join('');
}
function showAccountDetails(accountId, accountName) {
// Display account details in your app
// (No built-in account view - you build this yourself)
alert(`Selected: ${accountName} (${accountId})`);
// You could load more details via another CRM query
// or navigate to another page in your app
}
loadAccounts();
</script>
</body>
</html>
2. Canvas App (canvas
)
Embedded interactive component within presentations
Modes:
- Edit Mode - Canvas author configures the app
- Fullscreen Mode - User views canvas in fullscreen
- Presentation Mode - Active presentation to customer
Toolbar Shortcuts: Apps can add custom toolbar buttons for each mode.
typescript
shortcuts: {
fullscreen: [
{ id: 'refresh', icon: 'refresh', tooltip: 'Refresh Data' }
],
presentation: [
{ id: 'save', icon: 'save', tooltip: 'Save Configuration' }
],
edit: [
{ id: 'configure', icon: 'settings', tooltip: 'App Settings' }
]
}
Code Example:
html
<!-- canvas.html -->
<!DOCTYPE html>
<html>
<head>
<title>Product Configurator</title>
<script src="https://cdn.jsdelivr.net/npm/@pitcher/js-api"></script>
<style>
.configurator {
padding: 20px;
font-family: Arial, sans-serif;
}
.product-option {
margin: 10px 0;
padding: 10px;
border: 1px solid #ddd;
border-radius: 4px;
}
.price {
font-size: 24px;
font-weight: bold;
color: #2196F3;
}
</style>
</head>
<body>
<div class="configurator">
<h2>Configure Your Product</h2>
<div class="product-option">
<label>
Color:
<select id="color" onchange="updatePrice()">
<option value="black">Black (+$0)</option>
<option value="white">White (+$50)</option>
<option value="red">Red (+$100)</option>
</select>
</label>
</div>
<div class="product-option">
<label>
Storage:
<select id="storage" onchange="updatePrice()">
<option value="128">128GB (+$0)</option>
<option value="256">256GB (+$200)</option>
<option value="512">512GB (+$400)</option>
</select>
</label>
</div>
<div class="product-option">
<div class="price">Total: $<span id="price">999</span></div>
</div>
<button onclick="saveConfiguration()">Save Configuration</button>
</div>
<script>
const api = window.pitcher.useApi();
const basePrice = 999;
function updatePrice() {
const colorPrice = {
'black': 0,
'white': 50,
'red': 100
}[document.getElementById('color').value];
const storagePrice = {
'128': 0,
'256': 200,
'512': 400
}[document.getElementById('storage').value];
const total = basePrice + colorPrice + storagePrice;
document.getElementById('price').textContent = total;
}
async function saveConfiguration() {
const config = {
color: document.getElementById('color').value,
storage: document.getElementById('storage').value,
price: document.getElementById('price').textContent
};
// Save to AppsDB
await api.setGlobalEntry(
'product-config',
config
);
alert('Configuration saved!');
}
// Listen for shortcut button clicks
api.on('shortcut_clicked', (event) => {
if (event.shortcut_id === 'refresh') {
location.reload();
} else if (event.shortcut_id === 'save') {
saveConfiguration();
}
});
</script>
</body>
</html>
3. Overlay App (overlay_app
)
Floating panel on top of canvas
Placement Options:
top-left
,top-center
,top-right
left
,center
,right
bottom-left
,bottom-center
,bottom-right
Code Example:
html
<!-- overlay.html -->
<!DOCTYPE html>
<html>
<head>
<title>Speaker Notes</title>
<script src="https://cdn.jsdelivr.net/npm/@pitcher/js-api"></script>
<style>
.notes-panel {
background: white;
border: 1px solid #ccc;
border-radius: 8px;
padding: 15px;
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
max-height: 380px;
overflow-y: auto;
}
.note {
margin-bottom: 10px;
padding: 8px;
background: #f5f5f5;
border-radius: 4px;
}
</style>
</head>
<body>
<div class="notes-panel">
<h3>Speaker Notes</h3>
<div id="notes"></div>
</div>
<script>
const api = window.pitcher.useApi();
let currentPage = 0;
const pageNotes = {
0: "Welcome the customer. Introduce yourself and Pitcher.",
1: "Highlight key product features. Ask about their needs.",
2: "Show pricing. Be ready to discuss discounts.",
3: "Wrap up. Next steps and follow-up meeting."
};
function showNotes(pageIndex) {
const notesDiv = document.getElementById('notes');
const note = pageNotes[pageIndex] || "No notes for this page.";
notesDiv.innerHTML = `<div class="note">${note}</div>`;
}
// Listen for page changes
api.on('canvas_page_changed', (event) => {
currentPage = event.page_index;
showNotes(currentPage);
});
// Initialize
showNotes(0);
</script>
</body>
</html>
4. Admin Instance App (admin_instance
)
Extensions to admin panel
Use Cases:
- Configure CRM connection settings
- Manage custom metadata fields
- View license usage
- Configure third-party integrations
5. Section Execution App (canvas_section_execution
)
Runs when a section is displayed
Use Cases:
- Load dynamic content when section appears
- Track section-specific engagement
- Section-level forms/interactions
- A/B testing per section
Pitcher SDK API Reference
The Pitcher JavaScript SDK provides a unified API for interacting with the platform. Import it from @pitcher/js-api
:
typescript
import { useApi } from '@pitcher/js-api'
const api = useApi() // Automatically detects your embed location
Or via CDN (UMD):
html
<script src="https://cdn.jsdelivr.net/npm/@pitcher/js-api"></script>
<script>
const api = window.pitcher.useApi()
</script>
📚 Full API Reference: See the complete JS API documentation for all available methods.
Core Methods
typescript
// Get platform environment info
const env = await api.getEnv()
// Returns: {
// mode: 'IOS' | 'ANDROID' | 'WEB'
// platform: 'impact' | 'admin'
// pitcher: {
// accessToken: string
// instanceId: string
// apiOrigin: string
// user: { id, first_name, last_name, ... }
// }
// }
Opening Files
typescript
// Open a file (Impact API - usePitcherApi)
await api.open({ fileId: 'file-123' })
// Open file at specific page
await api.open({
fileId: 'file-789',
pageIndex: 5
})
// Open video at specific timestamp
await api.open({
fileId: 'video-123',
startTime: 45 // seconds
})
// UI API ONLY - Open canvas in overlay modal
// Only available when using useUi() or useApi() in UI context
await api.openCanvasOverlay({
id: 'canvas-456',
edit_mode: false,
fullscreen: true
})
// With custom positioning
await api.openCanvasOverlay({
id: 'canvas-789',
position: {
top: '10px',
left: '20px',
right: '20px',
bottom: '10px'
}
})
CRM Integration (Optional)
Note: CRM features are only available if your organization has CRM integration enabled. This uses Salesforce's SOQL queries via jsforce.
typescript
// Query Salesforce accounts
const result = await api.crmQuery({
query: 'SELECT Id, Name, Industry FROM Account LIMIT 10'
})
console.log(result.records) // Array of Account records
// Query with filters
const contacts = await api.crmQuery({
query: "SELECT Id, Name, Email FROM Contact WHERE AccountId = '001xx000003DGb2AAG'"
})
// Query opportunities
const opportunities = await api.crmQuery({
query: 'SELECT Id, Name, Amount, StageName FROM Opportunity WHERE CloseDate = THIS_YEAR'
})
📖 Learn more: See SOQL documentation for query syntax.
Data Persistence
Apps need to implement their own data persistence strategy:
typescript
// Option 1: Use browser localStorage (client-side only)
localStorage.setItem('myapp-config', JSON.stringify({ theme: 'dark' }))
const config = JSON.parse(localStorage.getItem('myapp-config') || '{}')
// Option 2: Store data in Pitcher using the REST API
const env = await api.getEnv()
const response = await fetch(`${env.pitcher.apiOrigin}/api/v1/your-storage/`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${env.pitcher.access_token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ key: 'config', value: { theme: 'dark' } })
})
Events & Broadcasting
typescript
// Listen to platform events
api.on('canvas_opened', (data) => {
console.log('Canvas opened:', data.body.canvas_id)
})
api.on('canvas_closed', (data) => {
console.log('Canvas closed:', data.body.canvas_id)
})
api.on('canvas_next_button_clicked', (data) => {
console.log('Next clicked, page:', data.body.current_page_index)
})
api.on('canvas_previous_button_clicked', (data) => {
console.log('Previous clicked, page:', data.body.current_page_index)
})
api.on('route_changed', (data) => {
console.log('Route:', data.body.route_path)
})
// Broadcast custom events (iOS multipeer connectivity)
api.broadcast({
type: 'CUSTOM_EVENT_NAME',
body: {
customData: 'value',
timestamp: Date.now()
}
})
REST API Access
Access the Pitcher REST API using the access token from getEnv()
:
typescript
const env = await api.getEnv()
// Get canvases
const canvases = await fetch(
`${env.pitcher.apiOrigin}/api/v1/canvases/`,
{
headers: {
'Authorization': `Bearer ${env.pitcher.accessToken}`,
'Content-Type': 'application/json'
}
}
)
// Get files
const files = await fetch(
`${env.pitcher.apiOrigin}/api/v1/files/`,
{
headers: { 'Authorization': `Bearer ${env.pitcher.accessToken}` }
}
)
// Create canvas
const newCanvas = await fetch(
`${env.pitcher.apiOrigin}/api/v1/canvases/`,
{
method: 'POST',
headers: {
'Authorization': `Bearer ${env.pitcher.accessToken}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
name: 'My New Canvas',
instance_id: env.pitcher.instanceId,
content: []
})
}
)
📖 REST API Documentation: https://pitcher.readme.io/
Note: CRM data (Accounts, Contacts, Opportunities) is accessed via
api.crmQuery()
using SOQL, not REST endpoints.
App Development Workflow
Development Steps
- Develop locally - Use any web development stack
- Test with SDK - Mock Pitcher SDK during development
- Create manifest - Define
app.json
with modules and settings - Package - ZIP all files
- Upload - Upload ZIP as File in Pitcher
- Install - Install app to Instance
- Configure - Admin configures app settings
- Embed - Add app to canvases or access as UI app
- Test - Test in real scenarios
- Iterate - Update and re-upload as needed
Real-World App Examples
Example 1: ROI Calculator (Canvas App)
Purpose: Help sales reps show ROI to customers
Module: canvas
Features:
- Input customer metrics
- Calculate savings/value
- Generate PDF report
- Save to customer account
Example 2: Meeting Scheduler (UI App + CRM Integration)
Purpose: Schedule meetings with CRM sync
Module: ui_app
Features:
- Calendar view
- Sync with Salesforce events
- Link to accounts
- Attach canvases
- Send invites
Example 3: Live Pricing Engine (Canvas App + External API)
Purpose: Show real-time pricing with discounts
Module: canvas
Features:
- Connect to pricing API
- Apply discounts dynamically
- Show competitor pricing
- Generate quotes
- Save to CRM opportunity
Example 4: Customer Feedback Form (Overlay App)
Purpose: Collect feedback during presentation
Module: overlay_app
Features:
- Quick rating (1-5 stars)
- Comments field
- Submit to CRM
- Track per-page ratings
Example 5: Analytics Dashboard (UI App)
Purpose: View content performance
Module: ui_app
Features:
- Top-performing files
- User engagement
- Canvas analytics
- Export reports
Security & Permissions
Apps inherit the permissions of the authenticated user:
- Access Token - OAuth token for API calls
- Instance Scope - Only access current instance data
- User Permissions - Respect user roles (Admin/Editor/Member)
- CRM Access - Only available if organization has CRM integration enabled (optional feature)
Best Practices:
- Never store access tokens client-side
- Use HTTPS for all external API calls
- Validate user input
- Follow OAuth best practices for CRM integrations (when enabled)
Summary
Pitcher Apps transform the platform from a presentation tool into a full application ecosystem:
- Flexible - Multiple embed locations for different use cases
- Powerful - Full JavaScript SDK with rich API
- Integrated - Deep CRM and platform integration
- Customizable - Settings framework for configuration
- Scalable - Distribute to entire organization
Apps make Pitcher infinitely extensible - limited only by imagination! 🚀