Explore optional advanced configuration options to enhance your Velt implementation with locations, contacts, and initialization state detection.

Locations

Users logged into the same Document ID can see each other’s Presence, Cursors, Comments etc. However, if you want to add another layer of categorization to organize users together, you can use Location.
If a Document is like a house, a Location is like a room within the house.
To learn more about Locations, check out its dedicated section here.

Contacts

When you reply to a comment, you can @mention other teammates that are added to a User's Contacts List. To learn more about creating a User's Contacts List, read here.

JWT Authentication Tokens

For enhanced security, you can use JWT tokens to authenticate users instead of passing user data directly in the client-side code. This provides an additional layer of security by verifying user identity on the server side. To learn more, see the JWT Tokens page.
Critical JWT Token Requirements:
  • JWT tokens must be generated server-side using your auth token from the Velt Console
  • Never expose JWT tokens or auth tokens in client-side code
  • Tokens expire after 48 hours and need to be refreshed
  • Include the JWT token in the authToken field when calling identify()

Step 1: Enable JWT Tokens in Console

First, enable JWT tokens in your Velt Console:
  1. Go to console.velt.dev
  2. Enable the toggle for Require JWT Token (listed at the bottom of the page)
JWT tokens won’t work unless you enable this setting in your console.

Step 2: Generate Auth Token

You need an auth token to generate JWT tokens. You can generate this from the Auth Token section in your Velt Console dashboard.
Store auth tokens securely on your server-side environment and never expose them in client-side code.
Auth tokens are long-lived and should be rotated periodically for security best practices.

Step 3: Create Server Endpoint for JWT Token Generation

Create a server endpoint that generates and serves JWT tokens to your client. See our generate_token API call for more information.
const express = require('express');
const app = express();
const PORT = 8080;

// Your credentials from Velt Console
const VELT_API_KEY = "YOUR_VELT_API_KEY";
const VELT_AUTH_TOKEN = "your-generated-auth-token-from-console";

async function generateVeltJWTToken(userId, config = {}) {
  const url = "https://api.velt.dev/v2/auth/generate_token";

  const body = {
    userId: userId,
    userProperties: {
      name: config.name,
      email: config.email,
      isAdmin: config.isAdmin || false
    },
    permissions: config.organizationId
      ? {
          resources: [
            { type: "organization", id: config.organizationId }
          ]
        }
      : undefined
  };

  try {
    const response = await fetch(url, {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        "x-velt-api-key": VELT_API_KEY,
        "x-velt-auth-token": VELT_AUTH_TOKEN
      },
      body: JSON.stringify(body),
    });

    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }

    const data = await response.json();
    return data?.result?.data?.token;
  } catch (error) {
    console.error("Error generating JWT token:", error);
    throw error;
  }
}

// Endpoint to generate JWT tokens
app.get('/generate-velt-jwt-token', async (req, res) => {
  try {
    const { userId, organizationId, name, email, isAdmin } = req.query;
    const token = await generateVeltJWTToken(userId, {
      organizationId,
      name,
      email,
      isAdmin: isAdmin === 'true'
    });
    res.json({ token });
  } catch (error) {
    res.status(500).json({ error: 'Failed to generate token' });
  }
});

app.listen(PORT, () => {
  console.log(`JWT Server listening on port ${PORT}`);
});

Token Refresh

JWT tokens expire after 48 hours from generation. Handle token expiration by subscribing to the error event and refreshing tokens when needed:
If you configured an Auth Provider on VeltProvider, token refresh is handled automatically. If you authenticate using the identify() method instead, you must listen for token_expired and re-authenticate with a fresh token as shown below.
import { useVeltEventCallback } from "@veltdev/react";

export default function AuthComponent() {
  const errorEvent = useVeltEventCallback('error');

  useEffect(() => {
    if (errorEvent?.code === "token_expired") {
      // Generate new JWT token from your server
      fetch("/api/auth/refresh-token")
        .then(res => res.json())
        .then(data => {
          // Re-authenticate with new token
          useIdentify(user, { authToken: data.newToken });
        });
    }
  }, [errorEvent]);

  return <div>Authentication Component</div>;
}
Security Benefits of JWT Tokens:
  • Server-side validation of user identity
  • Protection against client-side data manipulation
  • Secure user authentication without exposing sensitive data
  • Token expiration for enhanced security

Access the Velt Client

Access the core Velt client instance to call SDK APIs and subscribe to core events.

Core Velt Client methods at a glance

MethodDescriptionParamsReturnsReference
setDocuments()Subscribe to one or more documents. Supports rootDocumentId.documents: Document[], options?: SetDocumentsRequestOptionsPromise<void>/api-reference/sdk/api/api-methods#setdocuments
setRootDocument()Switch the current root document.document: DocumentPromise<void>N/A
setLocation()Set a single location (optionally as additional).location: Location, isAdditional?: booleanPromise<void>/key-concepts/overview#set-location
setLocations()Add multiple locations. Supports rootLocationId and appendLocation.locations: Location[], options?: SetLocationsRequestOptionsPromise<void>N/A
setRootLocation()Switch the current root location.location: LocationPromise<void>N/A
removeLocations()Remove multiple locations....locations: Location[]voidN/A
getVeltInitState()Subscribe to SDK initialization state.voidObservable<boolean>N/A
on()Subscribe to core events like initUpdate, error.eventType: stringObservable<any>N/A
getMetadata()Get current organization, document and location objects.voidPromise<VeltEventMetadata>N/A

Usage

import { useEffect } from 'react';
import { useVeltClient } from '@veltdev/react';

export default function CoreEventsListener() {
  const { client } = useVeltClient();

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

    // Listen to initialization updates
    const initSub = client.on('initUpdate').subscribe((event) => {
      console.log('Init update:', event);
    });

    // Listen to token lifecycle errors (e.g., token_expired)
    const errorSub = client.on('error').subscribe((error) => {
      console.log('Velt error:', error);
    });

    return () => {
      initSub?.unsubscribe();
      errorSub?.unsubscribe();
    };
  }, [client]);

  return null;
}
  • Use the React hook useVeltClient() inside components rendered under VeltProvider.
  • The client is available after initialization. In HTML/vanilla, call Velt.init() first.
  • Always unsubscribe from event subscriptions to avoid memory leaks.

Detect if Velt SDK is Initialized

This returns true when both the Velt User and Document are initialized.
import { useVeltInitState } from '@veltdev/react';

export default function MyComponent() {
  const veltInitState = useVeltInitState();

  useEffect(() => {
    console.log('Velt Init State:', veltInitState);
    if (veltInitState) {
      // Velt state is initialized, so user can perform any action here
    }
  }, [veltInitState]);

  return (
    <div>
      {/* Your component content */}
    </div>
  );
}