Skip to main content
Ensure that the data providers are set prior to calling identify method.

Overview

Velt supports self-hosting your users’ personally identifiable information (PII):
  • Only the userId is stored on Velt servers, keeping sensitive user metadata on your infrastructure
  • Velt Components automatically hydrate user details in the frontend by fetching from your configured data provider
  • This gives you full control over user data while maintaining all Velt functionality

How does it work?

  • When the SDK is initialized, it will call the UserDataProvider you configure with the list of userIds that it needs to fetch for the currently set user, organization, document, etc.
  • The UserDataProvider takes in a list of userIds and returns a Record object with the userIds as keys and the user data as values.

Implementation Approaches

You can implement user self-hosting using either of these approaches:
  1. Endpoint based: Provide an endpoint URL and let the SDK handle HTTP requests
  2. Function based: Implement the get method yourself
Both approaches are fully backward compatible and can be used together.
FeatureFunction basedEndpoint based
Best ForComplex setups requiring middleware logic, dynamic headers, or transformation before sendingStandard REST APIs where you just need to pass the request “as-is” to the backend
ImplementationYou write the fetch() or axios codeYou provide the url string and headers object
FlexibilityHighMedium
SpeedMediumHigh

Endpoint based DataProvider

Instead of implementing custom methods, you can configure an endpoint directly and let the SDK handle HTTP requests.

getConfig

Config-based endpoint for fetching users. The SDK automatically makes HTTP POST requests with the request body.
The config-based approach uses a different request format than the custom methods approach. It passes { organizationId, userIds } instead of just userIds.
const userConfig = {
  getConfig: {
    url: 'https://your-backend.com/api/velt/users/get',
    headers: { 'Authorization': 'Bearer YOUR_TOKEN' }
  },
  resolveUsersConfig: {
    organization: false,
    folder: false,
    document: true
  }
};

const userDataProvider = {
  config: userConfig
};

<VeltProvider
  apiKey='YOUR_API_KEY'
  dataProviders={{ user: userDataProvider }}
>
</VeltProvider>

Endpoint based Complete Example

const userConfig = {
  getConfig: {
    url: 'https://your-backend.com/api/velt/users/get',
    headers: { 'Authorization': 'Bearer YOUR_TOKEN' }
  },
  resolveUsersConfig: {
    organization: false,
    folder: false,
    document: true
  }
};

const userDataProvider = {
  config: userConfig
};

<VeltProvider
  apiKey='YOUR_API_KEY'
  dataProviders={{ user: userDataProvider }}
>
</VeltProvider>

Function based DataProvider

Here are the methods that you need to implement on the data provider:

get

Method to fetch users from your database.
Both response formats are supported for backward compatibility:
const fetchUsersFromDB = async (userIds) => {
  const response = await fetch('/api/velt/users/get', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ userIds })
  });
  return await response.json();
};

const userDataProvider = {
  get: fetchUsersFromDB,
};

<VeltProvider
  apiKey='YOUR_API_KEY'
  dataProviders={{ user: userDataProvider }}
>
</VeltProvider>

config

Configuration for the user data provider.
  • Type: ResolverConfig. Relevant properties:
    • resolveUsersConfig: ResolveUsersConfig. Controls whether Velt issues user-resolver requests during initialization to fetch contact lists at the organization, folder, and document levels. Use this to optimize performance in environments with a large number of users by preventing unnecessary user-data fetches. You can selectively disable user-resolver requests for specific scopes and instead provide your own user data via the custom autocomplete feature instead.
      • organization: boolean - Enable/disable user requests for organization users (default: true)
      • document: boolean - Enable/disable user requests for document users (default: true)
      • folder: boolean - Enable/disable user requests for folder users (default: true)
const userConfig = {
  resolveUsersConfig: {
    organization: false,
    folder: false,
    document: true
  }
};

Function based Complete Example

const fetchUsersFromDB = async (userIds) => {
  const response = await fetch('/api/velt/users/get', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ userIds })
  });
  return await response.json();
};

const userDataProvider = {
  get: fetchUsersFromDB,
  config: {
    resolveUsersConfig: {
      organization: false,
      folder: false,
      document: true
    }
  }
};

<VeltProvider
  apiKey='YOUR_API_KEY'
  dataProviders={{ user: userDataProvider }}
>
</VeltProvider>

Sample Data

{
    "USER_ID_1": {
        "userId": "USER_ID_1",
        "name": "John Doe",
        "email": "[email protected]",
        "photoUrl": "https://example.com/photos/john.jpg",
        "organizationId": "ORG_ID",
        "role": "admin"
    },
    "USER_ID_2": {
        "userId": "USER_ID_2",
        "name": "Jane Smith",
        "email": "[email protected]",
        "photoUrl": "https://example.com/photos/jane.jpg",
        "organizationId": "ORG_ID",
        "role": "member"
    }
}

Debugging

You can subscribe to dataProvider events to monitor and debug get operations. The event includes a moduleName field that identifies which module triggered the resolver call, helping you trace data provider requests. You can also use the Velt Chrome DevTools extension to inspect and debug your Velt implementation. Type: UserResolverModuleName
import { useVeltClient } from '@veltdev/react';

const { client } = useVeltClient();

useEffect(() => {
  if (!client) return;

  const subscription = client.on('dataProvider').subscribe((event) => {
    console.log('Data Provider Event:', event);
    console.log('Module Name:', event.moduleName);
  });

  return () => subscription?.unsubscribe();
}, [client]);