VRC WebSocket API (Draft WIP) - lolmaxz/vrc-ts GitHub Wiki

WebSocket API Documentation

The WebSocket API allows you to receive real-time updates from VRChat by establishing a WebSocket connection. This includes events related to users, friends, notifications, and groups. The VRCWebSocket class encapsulates the WebSocket connection and provides event handling for various VRChat events.


Table of Contents

  1. Introduction
  2. Getting Started
  3. Event Types
  4. Using the VRCWebSocket Class
  5. Event Payloads
  6. Example Usage
  7. Additional Types and Enums
  8. Notes

1. Introduction

The VRChat WebSocket API provides a way to receive real-time events and updates from the VRChat platform. By connecting to the WebSocket endpoint, you can listen for various events such as friend online/offline status, notifications, group updates, and more.

The VRCWebSocket class extends the standard WebSocket class and handles the connection to the VRChat WebSocket server. It manages heartbeat intervals, reconnections, and event parsing.


2. Getting Started

To use the WebSocket API, you need to:

  • Instantiate the VRCWebSocket class with your authenticated VRChatAPI instance or by specifying the URL and User-Agent manually.
  • Specify which events you want to listen to. (Default is all events.)
  • Implement event listeners to handle the incoming events, ensuring that you specify the correct types for TypeScript.

3. Event Types

The WebSocket API supports a wide range of event types, categorized as follows:

User Events

  • user-online: (Deprecated/Untested) Triggered when a user comes online.
  • user-update: Triggered when a user updates their information.
  • user-location: Triggered when a user changes their location (typically only for your own user).
  • user-offline: (Deprecated/Untested) Triggered when a user goes offline.

Friend Events

  • friend-online: Triggered when a friend comes online.
  • friend-active: Triggered when a friend is active (browsing the website but not in-game).
  • friend-update: Triggered when a friend updates their information.
  • friend-location: Triggered when a friend changes their location.
  • friend-offline: Triggered when a friend goes offline.
  • friend-add: Triggered when someone accepts your friend request.
  • friend-delete: Triggered when a friend removes you from their friends list.

Notification Events

Version 1 Notifications

  • notification: General notification event (Version 1).
  • friendRequest: Received a friend request.
  • requestInvite: Received a request to invite someone.
  • invite: Received an invite.
  • inviteResponse: Received an invite response.
  • requestInviteResponse: Received a response to your invite request.
  • votetokick: Received a vote-to-kick notification.

Version 2 Notifications

  • notification-v2: General notification event (Version 2).
  • group.announcement: Received a group announcement.
  • group.invite: Received a group invite.
  • group.informative: Received a group informative notification.
  • group.joinRequest: Received a group join request.

Group Events

  • group-joined: Triggered when you join a group.
  • group-left: Triggered when you leave a group.
  • group-member-updated: Triggered when a group member updates their information.
  • group-role-updated: Triggered when a group role is updated.

Special Events

  • content-refresh: Triggered when content related to you is refreshed.
  • error: Triggered when an error occurs.
  • Subgroups:
    • all: Listen to all events.
    • friend: Listen to all friend events.
    • user: Listen to all user events.
    • group: Listen to all group events.
    • notification-v1-all: Listen to all Version 1 notification events.
    • notification-v2-all: Listen to all Version 2 notification events.
    • notification-all: Listen to all notification events (both Version 1 and 2).

4. Using the VRCWebSocket Class

Constructor

Purpose

Initialize a new WebSocket connection to VRChat's WebSocket server.

Method Signature

constructor(options: {
  vrchatAPI?: VRChatAPI;
  eventsToListenTo?: EventType[];
  logAllEvents?: boolean;
  customURL?: string;
  customUserAgent?: string;
})

Parameters

  • options (object, required):

    • vrchatAPI (VRChatAPI, optional): An authenticated instance of the VRChatAPI class. If omitted, you must provide a custom WebSocket URL and User-Agent header.

    • eventsToListenTo (EventType[], optional):
      An array of event types you want to listen to. If omitted or empty, the WebSocket will listen to all events.

    • logAllEvents (boolean, optional):
      If true, all events received will be logged to the console. Default is false.

    • customURL (string, optional): A custom WebSocket URL to connect to. If omitted, the default VRChat WebSocket URL will be used. A User-Agent header is required for custom URLs (if no VRChatAPI instance is provided).

    • customUserAgent (string, optional): A custom User-Agent header to use when connecting to a custom WebSocket URL. Required if customURL is provided and no VRChatAPI instance is provided.

Example Usage

import { VRChatAPI, VRCWebSocket, EventType } from 'vrc-ts';

// Assume vrchatAPI is an authenticated instance of VRChatAPI
const vrchatAPI = new VRChatAPI("your_username", "your_password");

// Create a new VRCWebSocket instance to listen to friend events
const ws = new VRCWebSocket({
  vrchatAPI,
  eventsToListenTo: [EventType.Friend],
  logAllEvents: true,
});

// Add event listeners (see Event Handling section)

Event Handling

The VRCWebSocket class extends the standard WebSocket class and uses the EventEmitter pattern. You can add listeners for specific events using the on method. In TypeScript, it's important to specify the correct type for the event data to ensure type safety.

Example: Listening to Events with Correct Types

import {
  VRChatAPI,
  VRCWebSocket,
  EventType,
  FriendOnline,
  FriendOffline,
  NotificationWS,
} from 'vrc-ts';

// Listening to friend online event
ws.on(EventType.Friend_Online, (data: FriendOnline) => {
  console.log(`Friend ${data.user.displayName} came online at ${data.location}.`);
});

// Listening to friend offline event
ws.on(EventType.Friend_Offline, (data: FriendOffline) => {
  console.log(`Friend with userId ${data.userId} went offline.`);
});

// Listening to a notification event
ws.on(EventType.Notification, (notification: NotificationWS) => {
  console.log('Received a notification:', notification);
});

5. Event Payloads

Below are the payload structures for various events. These payloads are the data you receive when handling events.

User Events

user-location

type UserLocation = {
  userId: string;
  location: string;
  instance: string;
  worldId: string;
  user: UserBase;
  world: BaseWorld;
};
  • userId: The user's ID.
  • location: The full location string (e.g., wrld_xxx:12345).
  • instance: The instance ID.
  • worldId: The world ID.
  • user: The user object.
  • world: The world object.

user-update

type UserUpdate = {
  userId: string;
  user: UserUpdateWebSocket;
};
  • userId: The user's ID.
  • user: The updated user object.

Friend Events

friend-online

type FriendOnline = {
  userId: string;
  location: string;
  travelingToLocation: string;
  worldId: string;
  canRequestInvite: boolean;
  user: UserBase;
};
  • userId: The friend's user ID.
  • location: Current location.
  • travelingToLocation: Location the friend is traveling to.
  • worldId: The world ID.
  • canRequestInvite: Whether you can request an invite.
  • user: The user object.

friend-offline

type FriendOffline = {
  userId: string;
};
  • userId: The friend's user ID.

Notification Events

Version 1 Notifications

notification
type NotificationWS = NotificationBase & {
  details: object;
};
  • id: Notification ID.
  • type: Notification type (e.g., friendRequest, invite).
  • senderUserId: Sender's user ID.
  • message: Notification message.
  • details: Additional details (parsed object).

Version 2 Notifications

notification-v2
type NotificationV2Types =
  | NotificationV2GroupAnnouncement
  | NotificationV2GroupInformative
  | NotificationV2GroupInvite
  | NotificationV2GroupJoinRequest;
  • id: Notification ID.
  • type: Notification type (e.g., group.announcement).
  • data: Event-specific data.

Group Events

group-joined

type GroupJoined = {
  groupId: string;
};
  • groupId: The ID of the group you joined.

group-left

type GroupLeft = {
  groupId: string;
};
  • groupId: The ID of the group you left.

6. Example Usage

Listening to All Events with Correct Types

import {
  VRChatAPI,
  VRCWebSocket,
  EventType,
  FriendOnline,
  NotificationWS,
  FriendOffline,
} from 'vrc-ts';

const vrchatAPI = new VRChatAPI("your_username", "your_password");

const ws = new VRCWebSocket({
  vrchatAPI,
  eventsToListenTo: [EventType.All],
  logAllEvents: false,
});

ws.on(EventType.Friend_Online, (data: FriendOnline) => {
  console.log(`Friend ${data.user.displayName} is online at ${data.location}.`);
});

ws.on(EventType.Friend_Offline, (data: FriendOffline) => {
  console.log(`Friend ${data.userId} went offline.`);
});

ws.on(EventType.Notification, (notification: NotificationWS) => {
  console.log('Received a notification:', notification);
});

Listening to Specific Notifications with Correct Types

import {
  VRChatAPI,
  VRCWebSocket,
  EventType,
  InviteNotification,
  InviteResponseNotification,
} from 'vrc-ts';

const vrchatAPI = new VRChatAPI("your_username", "your_password");

const ws = new VRCWebSocket({
  vrchatAPI,
  eventsToListenTo: [EventType.Invite, EventType.Invite_Response],
});

ws.on(EventType.Invite, (invite: InviteNotification) => {
  console.log(`Received an invite from ${invite.senderUsername}: ${invite.message}`);
});

ws.on(EventType.Invite_Response, (response: InviteResponseNotification) => {
  console.log('Received an invite response:', response);
});

Listening to Group Events with Correct Types

import {
  VRChatAPI,
  VRCWebSocket,
  EventType,
  NotificationV2GroupInvite,
  NotificationV2GroupAnnouncement,
} from 'vrc-ts';

const vrchatAPI = new VRChatAPI("your_username", "your_password");

const ws = new VRCWebSocket({
  vrchatAPI,
  eventsToListenTo: [EventType.Group_Invite, EventType.Group_Announcement],
});

ws.on(EventType.Group_Invite, (invite: NotificationV2GroupInvite) => {
  console.log(`Received a group invite to ${invite.data.groupName} from ${invite.senderUsername}`);
});

ws.on(EventType.Group_Announcement, (announcement: NotificationV2GroupAnnouncement) => {
  console.log(`New announcement in ${announcement.data.groupName}: ${announcement.title}`);
});

7. Additional Types and Enums

EventType Enum

import { EventType } from 'vrc-ts';

enum EventType {
  User_Online = 'user-online',
  User_Update = 'user-update',
  User_Location = 'user-location',
  User_Offline = 'user-offline',
  Friend_Online = 'friend-online',
  Friend_Active = 'friend-active',
  Friend_Update = 'friend-update',
  Friend_Location = 'friend-location',
  Friend_Offline = 'friend-offline',
  Friend_Add = 'friend-add',
  Friend_Delete = 'friend-delete',
  Notification = 'notification',
  Notification_V2 = 'notification-v2',
  Notification_V2_Update = 'notification-v2-update',
  Notification_V2_Delete = 'notification-v2-delete',
  Hide_Notification = 'hide-notification',
  Response_Notification = 'response-notification',
  See_Notification = 'see-notification',
  Clear_Notification = 'clear-notification',
  Content_Refresh = 'content-refresh',
  Group_Join = 'group-joined',
  Group_Leave = 'group-left',
  Group_Member_Updated = 'group-member-updated',
  Group_Role_Updated = 'group-role-updated',
  Error = 'error',
  All = 'all',
  Friend = 'friend',
  User = 'user',
  Group = 'group',
  Notification_V1_All = 'notification-v1-all',
  Notification_V2_All = 'notification-v2-all',
  Notification_All = 'notification-all',
  Friend_Request = 'friendRequest',
  Request_Invite = 'requestInvite',
  Invite = 'invite',
  Invite_Response = 'inviteResponse',
  Request_Invite_Response = 'requestInviteResponse',
  Vote_To_Kick = 'votetokick',
  Group_Announcement = 'group.announcement',
  Group_Invite = 'group.invite',
  Group_Informative = 'group.informative',
  Group_Join_Request = 'group.joinRequest',
}

NotificationTypes Enum

import { NotificationTypes } from 'vrc-ts';

enum NotificationTypes {
  FRIEND_REQUEST = 'friendRequest',
  INVITE = 'invite',
  INVITE_RESPONSE = 'inviteResponse',
  REQUEST_INVITE = 'requestInvite',
  MESSAGE = 'message',
  REQUEST_INVITE_RESPONSE = 'requestInviteResponse',
  VOTE_TO_KICK = 'votetokick',
}

NotificationV2ResponseTypeEnum Enum

import { NotificationV2ResponseTypeEnum } from 'vrc-ts';

enum NotificationV2ResponseTypeEnum {
  Accept = 'accept',
  Decline = 'decline',
  Block = 'block',
  Unsubscribe = 'unsubscribe',
  Delete = 'delete',
  Reject = 'reject',
}

Event Payload Types

  • NotificationWS: Used for Version 1 notifications (EventType.Notification).
  • NotificationV2GroupInvite: Used for group invite notifications (EventType.Group_Invite).
  • FriendOnline: Used for friend online events (EventType.Friend_Online).
  • FriendOffline: Used for friend offline events (EventType.Friend_Offline).
  • Other types: Refer to the vrc-ts package documentation for additional event payload types.

UserBase Type

Refer to the Users API documentation in vrc-ts for the UserBase type structure.

BaseWorld Type

Refer to the Worlds API documentation in vrc-ts for the BaseWorld type structure.


8. Notes

  • TypeScript Type Safety: When using TypeScript, always specify the correct types for event data to ensure type safety and better development experience.
  • Event Handling: Ensure that you handle events appropriately and manage any asynchronous operations.
  • Reconnection Logic: The VRCWebSocket class includes reconnection logic with exponential backoff. If the connection is lost, it will attempt to reconnect automatically.
  • Heartbeat: The WebSocket connection includes a heartbeat mechanism to detect stale connections.
  • Deprecated/Untested Events: Some events are marked as deprecated or untested. They might not function as expected.
  • Logging: Use the logAllEvents option for debugging purposes to see all incoming events.
  • Event Filtering: Specify only the events you need in eventsToListenTo to optimize performance and reduce unnecessary processing.