Skip to main content
Watch for real-time updates to previewed components or content via a preview token.
Subscriptions are only useful for draft components and unpublished content, as published versions are immutable and will never change.

Subscription

subscription WatchPreview($token: String!) {
  previewUpdated(token: $token) {
    action
    timestamp
    preview {
      ... on ComponentPreview {
        componentId
        component {
          compiled
        }
        resolvedRef {
          package
          dependencies
        }
      }
      ... on ContentPreview {
        contentId
        content {
          compiled
        }
        resolvedRef {
          package
          dependencies
        }
      }
    }
  }
}

Parameters

ParameterTypeRequiredDescription
tokenString!YesPreview link token

Authentication

Use previewToken in connection params instead of x-api-key:
const client = createClient({
  url: 'wss://api.metabind.ai/graphql',
  connectionParams: {
    previewToken: 'YOUR_PREVIEW_TOKEN'
  }
});

Response: PreviewUpdate

FieldTypeDescription
previewPreviewResult!ComponentPreview or ContentPreview
actionString!”UPDATED” or “DELETED”
timestampDateTime!When the update occurred

ComponentPreview

FieldTypeDescription
componentIdID!Component ID
componentNameString!Component name for display/recents
componentComponentComponent data (null if exceeds 100KB)
resolvedRefResolvedPackageRef!Package IDs for caching

ContentPreview

FieldTypeDescription
contentIdID!Content ID
contentNameString!Content name for display/recents
contentTypeNameString!Content type name for display/recents
contentContentContent data (null if exceeds 100KB)
resolvedRefResolvedPackageRef!Package IDs for caching

Example

Variables

{
  "token": "abc123def456"
}

Component Update Payload

{
  "data": {
    "previewUpdated": {
      "action": "UPDATED",
      "timestamp": "2024-01-15T10:30:00Z",
      "preview": {
        "__typename": "ComponentPreview",
        "componentId": "comp123",
        "component": {
          "compiled": "const body = (props) => { ... }"
        },
        "resolvedRef": {
          "package": "draft:proj123:org456",
          "dependencies": []
        }
      }
    }
  }
}

Content Update Payload

{
  "data": {
    "previewUpdated": {
      "action": "UPDATED",
      "timestamp": "2024-01-15T10:30:00Z",
      "preview": {
        "__typename": "ContentPreview",
        "contentId": "cont123",
        "content": {
          "compiled": "const body = () => { ... }"
        },
        "resolvedRef": {
          "package": "draft:proj123:org456",
          "dependencies": ["xyz789ghi012..."]
        }
      }
    }
  }
}

Client Implementation

import { createClient } from 'graphql-ws';

const client = createClient({
  url: 'wss://api.metabind.ai/graphql',
  connectionParams: {
    previewToken: 'abc123def456'
  }
});

const unsubscribe = client.subscribe({
  query: `
    subscription WatchPreview($token: String!) {
      previewUpdated(token: $token) {
        action
        timestamp
        preview {
          ... on ComponentPreview {
            componentId
            component {
              compiled
            }
            resolvedRef {
              package
              dependencies
            }
          }
          ... on ContentPreview {
            contentId
            content {
              compiled
            }
            resolvedRef {
              package
              dependencies
            }
          }
        }
      }
    }
  `,
  variables: { token: 'abc123def456' }
}, {
  next: (data) => {
    const update = data.data.previewUpdated;

    if (update.action === 'DELETED') {
      if (update.preview.__typename === 'ComponentPreview') {
        removeComponentPreview(update.preview.componentId);
      } else {
        removeContentPreview(update.preview.contentId);
      }
      return;
    }

    // Handle updates based on type
    if (update.preview.__typename === 'ComponentPreview') {
      if (update.preview.component) {
        refreshComponentPreview(update.preview.component, update.preview.resolvedRef);
      } else {
        fetchComponent(update.preview.componentId).then(component => {
          refreshComponentPreview(component, update.preview.resolvedRef);
        });
      }
    } else if (update.preview.__typename === 'ContentPreview') {
      if (update.preview.content) {
        refreshContentPreview(update.preview.content, update.preview.resolvedRef);
      } else {
        fetchContent(update.preview.contentId).then(content => {
          refreshContentPreview(content, update.preview.resolvedRef);
        });
      }
    }

    // Fetch missing package data
    fetchMissingPackages([
      update.preview.resolvedRef.package,
      ...update.preview.resolvedRef.dependencies
    ]);
  },
  error: (err) => console.error('Subscription error:', err)
});

Handling Large Payloads

When data exceeds 100KB, the component or content field will be null:
if (update.preview.__typename === 'ComponentPreview') {
  if (!update.preview.component) {
    // Component exceeded 100KB - fetch separately
    const component = await fetchComponent(update.preview.componentId);
    refreshComponentPreview(component, update.preview.resolvedRef);
  }
}