Integrations

Data Binding

Connect design elements to spreadsheet data for dynamic content. Create templates that automatically update when data changes.

How Data Binding Works
Connect elements to live data sources
┌─────────────────────────────────────────────────────────────────────┐
│                      DATA BINDING FLOW                               │
├─────────────────────────────────────────────────────────────────────┤
│                                                                      │
│  ┌─────────────┐      ┌─────────────┐      ┌─────────────────────┐  │
│  │   Sheets    │      │   Binding   │      │    Design Element   │  │
│  │   Service   │ ───▶ │   Engine    │ ───▶ │    (Text, Image)    │  │
│  └─────────────┘      └─────────────┘      └─────────────────────┘  │
│                              │                                       │
│                              │                                       │
│                       ┌──────┴──────┐                               │
│                       │   Bindings   │                               │
│                       │   Config     │                               │
│                       └─────────────┘                               │
│                                                                      │
│  Flow:                                                               │
│  1. Create binding between element and cell/range                    │
│  2. Engine fetches data from Sheets service                          │
│  3. Element content updates automatically                            │
│  4. Changes in Sheets propagate in real-time (via webhooks)         │
│                                                                      │
└─────────────────────────────────────────────────────────────────────┘
Social Media Templates

Generate variants for different products or messages

Report Generation

Create charts and infographics from live data

Personalization

Customize designs with names, dates, or user data

Batch Export

Export multiple designs with different data

Connecting to Sheets
Access spreadsheet data from sheets.platphormnews.com
// List available sheets
// GET https://sheets.platphormnews.com/api/v1/sheets

const sheets = await fetch(
  'https://sheets.platphormnews.com/api/v1/sheets',
  { headers: { 'X-PlatPhorm-API-Key': apiKey } }
).then(r => r.json())

// {
//   sheets: [
//     {
//       id: "sheet_abc123",
//       name: "Product Catalog",
//       worksheets: ["Products", "Categories", "Prices"],
//       lastModified: "2024-01-15T10:00:00Z"
//     },
//     {
//       id: "sheet_def456",
//       name: "Marketing Copy",
//       worksheets: ["Headlines", "Descriptions", "CTAs"],
//       lastModified: "2024-01-14T15:00:00Z"
//     }
//   ]
// }
Creating Bindings
Link design elements to data cells
import { useDataBinding } from '@/hooks/use-data-binding'

function BindingPanel({ element }) {
  const { createBinding, bindings } = useDataBinding()

  const handleBind = async () => {
    await createBinding({
      elementId: element.id,
      property: 'content',  // Which property to bind
      source: {
        sheetId: 'sheet_abc123',
        worksheet: 'Products',
        cell: 'A2',         // or range: 'A2:A10'
      },
      transform: (value) => value.toUpperCase(), // Optional
    })
  }

  return (
    <div>
      <p>Bind &quot;{element.content}&quot; to sheet data</p>
      <SheetSelector onSelect={handleBind} />
    </div>
  )
}

// Binding interface
interface DataBinding {
  id: string
  elementId: string
  property: 'content' | 'src' | 'fill' | 'stroke'
  source: {
    sheetId: string
    worksheet: string
    cell: string
  }
  transform?: (value: any) => any
  fallback?: any  // Value if cell is empty
}
Batch Generation
Generate multiple designs from rows of data
// Generate design variants from sheet data

import { useBatchGenerate } from '@/hooks/use-batch-generate'

function BatchGenerator({ design }) {
  const { generate, isGenerating, progress } = useBatchGenerate()

  const handleGenerate = async () => {
    const results = await generate({
      designId: design.id,
      source: {
        sheetId: 'sheet_abc123',
        worksheet: 'Products',
        range: 'A2:D100',  // Each row becomes a variant
      },
      bindings: [
        { property: 'content', column: 'A', elementId: 'title_element' },
        { property: 'content', column: 'B', elementId: 'desc_element' },
        { property: 'content', column: 'C', elementId: 'price_element' },
        { property: 'src', column: 'D', elementId: 'image_element' },
      ],
      export: {
        format: 'png',
        preset: 'og-image',
        naming: 'row_{{A}}_og'  // Filename template
      }
    })

    // results: {
    //   total: 98,
    //   successful: 98,
    //   failed: 0,
    //   exports: [
    //     { rowIndex: 1, filename: 'row_Widget_Pro_og.png', url: '...' },
    //     { rowIndex: 2, filename: 'row_Widget_Mini_og.png', url: '...' },
    //     ...
    //   ],
    //   zipUrl: '...'  // All files in a ZIP
    // }
  }

  return (
    <div>
      <button onClick={handleGenerate} disabled={isGenerating}>
        {isGenerating ? `Generating... ${progress}%` : 'Generate All'}
      </button>
    </div>
  )
}
Real-time Updates
Automatically update when data changes
// Subscribe to sheet changes

import { useSheetSubscription } from '@/hooks/use-sheet-subscription'

function LiveDesign({ design, bindings }) {
  // Subscribe to changes in bound cells
  useSheetSubscription({
    sheetId: 'sheet_abc123',
    cells: bindings.map(b => b.source.cell),
    
    onUpdate: (updates) => {
      // Updates: [{ cell: 'A2', oldValue: '...', newValue: '...' }]
      
      for (const update of updates) {
        const binding = bindings.find(b => b.source.cell === update.cell)
        if (binding) {
          updateElement(binding.elementId, {
            [binding.property]: update.newValue
          })
        }
      }
    }
  })

  return <Canvas design={design} />
}

// Behind the scenes, this uses webhooks from the Sheets service
// Webhook event: sheets.cell.updated
// {
//   type: "sheets.cell.updated",
//   data: {
//     sheetId: "sheet_abc123",
//     worksheet: "Products",
//     cell: "A2",
//     oldValue: "Widget",
//     newValue: "Widget Pro"
//   }
// }
Template Variables
Use Mustache-style syntax in text content
// Instead of binding entire elements, use template variables

// Text element content with variables
const textElement = {
  id: 'text_001',
  type: 'text',
  content: 'Introducing {{product_name}} - {{tagline}}',
  // ...
}

// Define variable sources
const variables = {
  product_name: { sheetId, worksheet, cell: 'A2' },
  tagline: { sheetId, worksheet, cell: 'B2' },
}

// Apply template
await applyTemplate(design.id, variables)

// Result: "Introducing Widget Pro - The best widget ever"

// Supported syntax:
// {{variable}}         - Simple substitution
// {{variable|upper}}   - With filter (upper, lower, title, etc.)
// {{variable|default:"N/A"}} - With default value
// {{price|currency}}   - Format as currency
MCP Tools
AI agent access for data binding
// Available MCP tools for data binding

// Fetch data from sheet
await mcp.call('data_fetch', {
  sheetId: 'sheet_abc123',
  range: 'A1:D10'
})

// Create binding
await mcp.call('data_bind', {
  designId: 'design_current',
  elementId: 'text_001',
  property: 'content',
  sheetId: 'sheet_abc123',
  cell: 'A2'
})

// Remove binding
await mcp.call('data_unbind', {
  designId: 'design_current',
  elementId: 'text_001',
  property: 'content'
})

// Generate batch from sheet
await mcp.call('data_batch_generate', {
  designId: 'design_current',
  sheetId: 'sheet_abc123',
  range: 'A2:D100',
  exportFormat: 'png'
})
Best Practices
Tips for effective data binding

Design for Variable Content

Account for text length variations. Use auto-sizing text boxes or design for the longest expected content.

Validate Data

Always provide fallback values for empty cells. Validate URLs before binding to image elements.

Cache Appropriately

Sheet data is cached for performance. Force refresh when you need the latest data immediately.

Use Named Ranges

Named ranges in sheets make bindings more maintainable than cell references like A2.

Related Documentation