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!“update” or “delete”
timestampDateTime!When the update occurred

ComponentPreview

FieldTypeDescription
componentIdID!Component ID
componentComponentComponent data (null if exceeds 128KB)
resolvedRefResolvedPackageRef!Package IDs for caching

ContentPreview

FieldTypeDescription
contentIdID!Content ID
contentContentContent data (null if exceeds 128KB)
resolvedRefResolvedPackageRef!Package IDs for caching

Example

Variables

{
  "token": "abc123def456"
}

Component Update Payload

{
  "data": {
    "previewUpdated": {
      "action": "update",
      "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": "update",
      "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 === 'delete') {
      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 128KB, the component or content field will be null:
if (update.preview.__typename === 'ComponentPreview') {
  if (!update.preview.component) {
    // Component exceeded 128KB - fetch separately
    const component = await fetchComponent(update.preview.componentId);
    refreshComponentPreview(component, update.preview.resolvedRef);
  }
}