Skip to main content
Preview links allow accessing components and content via a shareable token without requiring an API key. This enables sharing draft work with stakeholders, testing components in isolation, and previewing unpublished content.

Authentication

Preview queries use a preview-token header instead of x-api-key:
headers: {
  'preview-token': 'YOUR_PREVIEW_TOKEN',
  'Content-Type': 'application/json'
}
For WebSocket subscriptions:
connectionParams: {
  previewToken: 'YOUR_PREVIEW_TOKEN'
}

Preview Query

query GetPreview($token: String!, $version: Int) {
  preview(token: $token, version: $version) {
    ... on ComponentPreview {
      componentId
      component {
        id
        name
        title
        compiled
        schema
      }
      resolvedRef {
        package
        dependencies
      }
    }
    ... on ContentPreview {
      contentId
      content {
        id
        name
        compiled
        contentType {
          name
          schema
        }
      }
      resolvedRef {
        package
        dependencies
      }
    }
  }
}

Parameters

ParameterTypeDescription
tokenString!Preview link token
versionIntOptional: specific component version

Component Preview

Fetch a component preview (defaults to latest draft):
query GetComponentPreview($token: String!) {
  preview(token: $token) {
    ... on ComponentPreview {
      componentId
      component {
        compiled
        schema
      }
      resolvedRef {
        package
        dependencies
      }
    }
  }
}
Response:
{
  "data": {
    "preview": {
      "__typename": "ComponentPreview",
      "componentId": "comp123",
      "component": {
        "compiled": "const body = (props) => { ... }",
        "schema": "{\"type\":\"object\",\"properties\":{...}}"
      },
      "resolvedRef": {
        "package": "draft:proj123:org456",
        "dependencies": ["xyz789ghi012..."]
      }
    }
  }
}

Specific Version

Fetch a specific published version of a component:
query GetComponentVersion($token: String!, $version: Int!) {
  preview(token: $token, version: $version) {
    ... on ComponentPreview {
      componentId
      component {
        compiled
      }
      resolvedRef {
        package
        dependencies
      }
    }
  }
}
Variables:
{
  "token": "abc123def456",
  "version": 2
}

Content Preview

Fetch a content preview:
query GetContentPreview($token: String!) {
  preview(token: $token) {
    ... on ContentPreview {
      contentId
      content {
        id
        name
        compiled
        tags
        locale
        contentType {
          name
        }
      }
      resolvedRef {
        package
        dependencies
      }
    }
  }
}

Preview Subscription

Watch for real-time updates to previewed components or content:
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
        }
      }
    }
  }
}
Subscriptions are only useful for draft components and unpublished content, as published versions are immutable.

Client Implementation

React Hook Example

import { useQuery, useSubscription } from '@apollo/client';

function usePreview(token, version) {
  const { data, loading, error } = useQuery(GET_PREVIEW, {
    variables: { token, version },
    context: {
      headers: { 'preview-token': token }
    }
  });

  useSubscription(PREVIEW_UPDATED, {
    variables: { token },
    context: {
      headers: { 'preview-token': token }
    },
    onData: ({ data }) => {
      const update = data.data.previewUpdated;
      // Handle update...
    }
  });

  return { data: data?.preview, loading, error };
}

WebSocket Setup for Previews

import { createClient } from 'graphql-ws';

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

previewClient.subscribe({
  query: PREVIEW_UPDATED_SUBSCRIPTION,
  variables: { token: 'YOUR_PREVIEW_TOKEN' }
}, {
  next: (data) => {
    const update = data.data.previewUpdated;

    if (update.action === 'delete') {
      handlePreviewDeleted(update.preview);
      return;
    }

    // Handle component or content update
    if (update.preview.__typename === 'ComponentPreview') {
      refreshComponentPreview(update.preview);
    } else {
      refreshContentPreview(update.preview);
    }
  },
  error: (err) => console.error('Preview subscription error:', err)
});

Handling Large Payloads

When content exceeds the 128KB WebSocket limit:
  1. The component or content field will be null
  2. The resolvedRef is always included
  3. Fetch the full data separately using the component/content ID
if (!update.preview.component) {
  // Component exceeded 128KB
  const component = await fetchComponent(update.preview.componentId);
  refreshComponentPreview(component, update.preview.resolvedRef);
} else {
  refreshComponentPreview(update.preview.component, update.preview.resolvedRef);
}

Error Handling

Invalid Token

{
  "errors": [
    {
      "message": "Invalid or expired preview token",
      "extensions": {
        "code": "INVALID_PREVIEW_TOKEN"
      },
      "path": ["preview"]
    }
  ],
  "data": { "preview": null }
}

Version Not Found

{
  "errors": [
    {
      "message": "Component version not found",
      "extensions": {
        "code": "VERSION_NOT_FOUND",
        "version": 5
      },
      "path": ["preview"]
    }
  ],
  "data": { "preview": null }
}

Preview Resource Deleted

{
  "errors": [
    {
      "message": "Preview resource not found or deleted",
      "extensions": {
        "code": "PREVIEW_NOT_FOUND"
      },
      "path": ["preview"]
    }
  ],
  "data": { "preview": null }
}