Skip to main content
  • This feature is currently in beta and is subject to change.
  • This is currently only compatible with setDocuments method.
  • Ensure that the data providers are set prior to calling identify method.
  • The data provider methods must return the correct status code (e.g. 200 for success, 500 for errors) and success boolean in the response object. This ensures proper error handling and retries.

Overview

Velt supports self-hosting your reactions and related data:
  • Reactions can be stored on your own infrastructure, with only necessary identifiers on Velt servers.
  • Velt Components automatically hydrate reaction data in the frontend by fetching from your configured data provider.
  • This gives you full control over reaction data while maintaining all Velt collaboration features.
  • This automatically also ensures that the in-app notifications content related to reactions is not stored on Velt servers. The content is generated using the reactions data in the frontend.

How does it work?

  • When reactions are created, updated, deleted or requested, the SDK uses your configured ReactionAnnotationDataProvider to handle storage and retrieval
  • The data provider implements get, save, and delete methods to interact with your database
  • Velt handles the data mapping and realtime synchronization while delegating persistence of actual content to your infrastructure
  • The data provider works at the Reaction Annotation level.
  • For write requests (save, delete), the operation is first performed on your database and only if we get a success response, the SDK will perform the operation on the Velt server. If the operation fails on your database, the SDK will not perform the operation on the Velt server.
  • You can configure retries, timeouts, etc. for the data provider.
Here are the methods that you need to implement on the data provider:

get

Method to fetch reactions from your database. On error we will retry.
  • Sample Request
  • Sample Response
  • Error Response
{
  "organizationId": "your-org-id",
  "documentIds": ["doc-123", "doc-456"],
  "folderId": "folder-789"
}
Or fetch specific reaction annotations:
{
  "organizationId": "your-org-id",
  "reactionAnnotationIds": ["reaction-abc", "reaction-xyz"]
}

save

Save reactions to your database. Return a success or error response. On error we will retry.
  • Sample Request
  • Sample Response
  • Error Response
{
  "reactionAnnotation": {
    "reaction-abc": {
      "annotationId": "reaction-abc",
      "metadata": {
        "apiKey": "your-api-key",
        "documentId": "doc-123",
        "organizationId": "your-org-id",
        "folderId": "folder-789"
      },
      "reactions": {
        "👍": [
          {
            "userId": "user-1",
            "reactionId": "reaction-1"
          }
        ]
      }
    }
  },
  "metadata": {
    "apiKey": "your-api-key",
    "documentId": "doc-123",
    "organizationId": "your-org-id"
  },
  "event": "onReactionAdd"
}

delete

Delete reactions from your database. Return a success or error response. On error we will retry.
  • Sample Request
  • Sample Response
  • Error Response
{
  "reactionAnnotationId": "reaction-abc",
  "metadata": {
    "apiKey": "your-api-key",
    "documentId": "doc-123",
    "organizationId": "your-org-id",
    "folderId": "folder-789"
  },
  "event": "onReactionDelete"
}

config

Configuration for the reaction data provider.

MongoDB Backend Implementation Example

Here’s how to implement the data provider methods with MongoDB:
  • Schema Definition
  • Get Method
  • Save Method
  • Delete Method
  • Complete Setup
// MongoDB Schema for Reaction Annotations
interface ReactionAnnotationDocument {
  annotationId: string;
  metadata: {
    apiKey: string;
    documentId: string;
    organizationId: string;
    folderId?: string;
  };
  reactions: {
    [emoji: string]: Array<{
      userId: string;
      reactionId: string;
    }>;
  };
  createdAt?: Date;
  updatedAt?: Date;
}

Example Implementation

  • React / Next.js
  • Other Frameworks
const fetchReactionsFromDB = async (request: GetReactionResolverRequest) => {
    // Fetch reaction annotations from your DB
    const result = await __getReactionsFromYourDB__(request)
      .then((response) => {
        return { data: response, success: true, statusCode: 200 };
      })
      .catch((error) => {
        return { success: false, statusCode: 500 };
      });

    return result;
};

const saveReactionsToDB = async (request: SaveReactionResolverRequest) => {
    const result = await __saveReactionsToYourDB__(request)
      .then((response) => {
        return { success: true, statusCode: 200 };
      })
      .catch((error) => {
        return { success: false, statusCode: 500 };
    });
    return result;
};

const deleteReactionsFromDB = async (request: DeleteReactionResolverRequest) => {
    const result = await __deleteReactionsFromYourDB__(request)
      .then((response) => {
        return { success: true, statusCode: 200 };
      })
      .catch((error) => {
        return { success: false, statusCode: 500 };
    });
    return result;
};

const reactionResolverConfig: ResolverConfig = {
    resolveTimeout: 2000,
    getRetryConfig: {
        retryCount: 3,
        retryDelay: 2000
    },
    saveRetryConfig: {
        retryCount: 3,
        retryDelay: 2000
    },
    deleteRetryConfig: {
        retryCount: 3,
        retryDelay: 2000
    }
};


const reactionAnnotationDataProvider: ReactionAnnotationDataProvider = {
    get: fetchReactionsFromDB,
    save: saveReactionsToDB,
    delete: deleteReactionsFromDB,
    config: reactionResolverConfig
};

<VeltProvider
    apiKey='YOUR_API_KEY'
    dataProviders={{
        reaction: reactionAnnotationDataProvider
    }}
>
</VeltProvider>

Sample Data

  • Stored on your database
  • Stored on Velt servers
{
    "REACTION_ANNOTATION_ID": {
        "annotationId": "REACTION_ANNOTATION_ID",
        "metadata": {
            "apiKey": "API_KEY",
            "documentId": "DOCUMENT_ID",
            "organizationId": "ORGANIZATION_ID",
            "folderId": "FOLDER_ID"
        },
        "reactions": {
            "👍": [
                {
                    "userId": "USER_ID_1",
                    "reactionId": "REACTION_ID_1"
                }
            ],
            "❤️": [
                {
                    "userId": "USER_ID_2",
                    "reactionId": "REACTION_ID_2"
                }
            ]
        }
    }
}