---
meta:
  title: "Webhook events"
  parentTitle: "API Reference"
  description: "API reference for Liveblocks webhook event payloads."
alwaysShowAllNavigationLevels: false
---

## Liveblocks events

An event occurs when a change is made to Liveblocks data. Each endpoint you
provide in the webhooks dashboard listens to all events by default but can be
easily configured to only listen to a subset by updating the Message Filtering
section.

To configure an endpoint, verify requests, and test locally, read the
[Webhooks platform guide](/docs/platform/webhooks).

The Event Catalog in the webhooks dashboard provides a list of events available
for subscription, along with their schema.

Events available for use include:

- `StorageUpdated`
- `UserEntered/UserLeft`
- `RoomCreated/RoomDeleted`
- `YDocUpdated`
- `CommentCreated/CommentEdited/CommentDeleted/CommentMetadataUpdated`
- `CommentReactionAdded/CommentReactionRemoved`
- `ThreadCreated/ThreadDeleted/ThreadMetadataUpdated`
- `Notification`

More events will come later, such as:

- `MaxConnectionsReached`

## UserEnteredEvent

When a user connects to a room, an event is triggered, indicating that the user
has entered. The `numActiveUsers` field shows the number of users in the room
after the user has joined. This event is not throttled.

```ts
// Schema
type UserEnteredEvent = {
  type: "userEntered";
  data: {
    projectId: string;
    roomId: string;
    connectionId: number;
    userId: string | null;
    userInfo: Record<string, any> | null;
    enteredAt: string;
    numActiveUsers: number;
  };
};

// Example
const userEnteredEvent = {
  type: "userEntered",
  data: {
    projectId: "my-project-id",
    roomId: "my-room-id",
    connectionId: 4,
    userId: "a-user-id",
    userInfo: null,
    enteredAt: "2021-10-06T01:45:56.558Z",
    numActiveUsers: 8,
  },
};
```

## UserLeftEvent

A user leaves a room when they disconnect from a room, which is when this event
is triggered. The `numActiveUsers` field represents the number of users in the
room after the user has left. This event, like `UserEntered`, is not throttled.

```ts
// Schema
type UserLeftEvent = {
  type: "userLeft";
  data: {
    projectId: string;
    roomId: string;
    connectionId: number;
    userId: string | null;
    userInfo: Record<string, any> | null;
    leftAt: string;
    numActiveUsers: number;
  };
};

// Example
const userLeftEvent = {
  type: "userLeft",
  data: {
    projectId: "my-project-id",
    roomId: "my-room-id",
    connectionId: 4,
    userId: "a-user-id",
    userInfo: {
      name: "John Doe",
    },
    leftAt: "2021-10-06T01:45:56.558Z",
    numActiveUsers: 7,
  },
};
```

## StorageUpdatedEvent

Storage is updated when a user writes to Storage. This event is throttled at 60
seconds and, as such, may not be triggered for every write.

For example, if a user writes to Storage at 1:00 pm sharp, the
`StorageUpdatedEvent` event will be triggered shortly after. If the user writes
to Storage again at 1:00 pm and 2 seconds, the `StorageUpdatedEvent` event will
be triggered 60 seconds after the first event was sent, around 1:01 pm.

On [Enterprise plans](/pricing) we can increase the throttle rate.

```ts
// Schema
type StorageUpdatedEvent = {
  type: "storageUpdated";
  data: {
    roomId: string;
    projectId: string;
    updatedAt: string;
  };
};

// Example
const storageUpdatedEvent = {
  type: "storageUpdated",
  data: {
    projectId: "my-project-id",
    roomId: "my-room-id",
    updatedAt: "2021-10-06T01:45:56.558Z", // 👈 time of the last write
  },
};
```

## RoomCreatedEvent

An event is triggered when a room is created. This event is not throttled. There
are two ways for rooms to be created:

- By calling the
  [create room API](/docs/api-reference/rest-api-endpoints#post-rooms)
- When a user connects to a room that does not exist

```ts
// Schema
type RoomCreatedEvent = {
  type: "roomCreated";
  data: {
    projectId: string;
    roomId: string;
    createdAt: string;
  };
};

// Example
const roomCreatedEvent = {
  type: "roomCreated",
  data: {
    projectId: "my-project-id",
    roomId: "my-room-id",
    createdAt: "2021-10-06T01:45:56.558Z",
  },
};
```

## RoomDeletedEvent

An event is triggered when a room is deleted. This event is not throttled.

```ts
// Schema
type RoomDeletedEvent = {
  type: "roomDeleted";
  data: {
    projectId: string;
    roomId: string;
    deletedAt: string;
  };
};

// Example
const roomDeletedEvent = {
  type: "roomDeleted",
  data: {
    projectId: "my-project-id",
    roomId: "my-room-id",
    deletedAt: "2021-10-06T01:45:56.558Z",
  },
};
```

## YDocUpdatedEvent

Yjs document is updated when a user makes a change to a Yjs doc connected to a
room. This event is throttled at sixty seconds and, as such, may not be
triggered for every write.

For example, if a user updates a Yjs document at 1:00 pm sharp, the
`YDocUpdatedEvent` event will be triggered shortly after. If the user writes to
the Yjs document again at 1:00 pm and 2 seconds, the `YDocUpdatedEvent` event
will be triggered 60 seconds after the first event was sent, around 1:01 pm

On [Enterprise plans](/pricing) we can increase the throttle rate.

```ts
// Schema
type YDocUpdatedEvent = {
  type: "ydocUpdated";
  data: {
    projectId: string;
    roomId: string;
    updatedAt: string;
  };
};

// Example
const ydocUpdatedEvent = {
  type: "ydocUpdated",
  data: {
    projectId: "my-project-id",
    roomId: "my-room-id",
    updatedAt: "2013-06-26T19:10:19Z",
  },
};
```

## CommentCreatedEvent

An event is triggered when a comment is created. This event is not throttled.

```ts
// Schema
type CommentCreatedEvent = {
  type: "commentCreated";
  data: {
    projectId: string;
    roomId: string;
    threadId: string;
    commentId: string;
    createdAt: string;
    createdBy: string;
  };
};

// Example
const commentCreatedEvent = {
  type: "commentCreated",
  data: {
    projectId: "my-project-id",
    roomId: "my-room-id",
    threadId: "my-thread-id",
    commentId: "my-comment-id",
    createdAt: "2021-10-06T01:45:56.558Z",
    createdBy: "my-user-id",
  },
};
```

## CommentEditedEvent

An event is triggered when a comment is edited. This event is not throttled.

```ts
// Schema
type CommentEditedEvent = {
  type: "commentEdited";
  data: {
    projectId: string;
    roomId: string;
    threadId: string;
    commentId: string;
    editedAt: string;
  };
};

// Example
const commentEditedEvent = {
  type: "commentEdited",
  data: {
    projectId: "my-project-id",
    roomId: "my-room-id",
    threadId: "my-thread-id",
    commentId: "my-comment-id",
    editedAt: "2021-10-06T01:45:56.558Z",
  },
};
```

## CommentDeletedEvent

An event is triggered when a comment is deleted. This event is not throttled.

```ts
// Schema
type CommentDeletedEvent = {
  type: "commentDeleted";
  data: {
    projectId: string;
    roomId: string;
    threadId: string;
    commentId: string;
    deletedAt: string;
  };
};

// Example
const commentDeletedEvent = {
  type: "commentDeleted",
  data: {
    projectId: "my-project-id",
    roomId: "my-room-id",
    threadId: "my-thread-id",
    commentId: "my-comment-id",
    deletedAt: "2021-10-06T01:45:56.558Z",
  },
};
```

## CommentReactionAddedEvent

An event is triggered when a reaction is added to a comment. This event is not
throttled.

```ts
// Schema
type CommentReactionAddedEvent = {
  type: "commentReactionAdded";
  data: {
    projectId: string;
    roomId: string;
    threadId: string;
    commentId: string;
    emoji: string;
    addedAt: string;
    addedBy: string;
  };
};

// Example
const commentReactionAddedEvent = {
  type: "commentReactionAdded",
  data: {
    projectId: "my-project-id",
    roomId: "my-room-id",
    threadId: "my-thread-id",
    commentId: "my-comment-id",
    emoji: "👍",
    addedAt: "2021-10-06T01:45:56.558Z",
    addedBy: "my-user-id",
  },
};
```

## CommentReactionRemovedEvent

An event is triggered when a reaction is removed from a comment. This event is
not throttled.

```ts
// Schema
type CommentReactionRemovedEvent = {
  type: "commentReactionRemoved";
  data: {
    projectId: string;
    roomId: string;
    threadId: string;
    commentId: string;
    emoji: string;
    removedAt: string;
    removedBy: string;
  };
};

// Example
const commentReactionRemovedEvent = {
  type: "commentReactionRemoved",
  data: {
    projectId: "my-project-id",
    roomId: "my-room-id",
    threadId: "my-thread-id",
    commentId: "my-comment-id",
    emoji: "👍",
    removedAt: "2021-10-06T01:45:56.558Z",
    removedBy: "my-user-id",
  },
};
```

## ThreadCreatedEvent

An event is triggered when a thread is created. This event is not throttled.

```ts
// Schema
type ThreadCreatedEvent = {
  type: "threadCreated";
  data: {
    projectId: string;
    roomId: string;
    threadId: string;
    createdAt: string;
    createdBy: string;
  };
};

// Example
const threadCreatedEvent = {
  type: "threadCreated",
  data: {
    projectId: "my-project-id",
    roomId: "my-room-id",
    threadId: "my-thread-id",
    createdAt: "2021-10-06T01:45:56.558Z",
    createdBy: "my-user-id",
  },
};
```

## ThreadDeletedEvent

An event is triggered when a thread is deleted. This event is not throttled. A
thread is deleted when all comments in the thread are deleted or when the thread
is manually deleted.

```ts
// Schema
type ThreadDeletedEvent = {
  type: "threadDeleted";
  data: {
    projectId: string;
    roomId: string;
    threadId: string;
    deletedAt: string;
  };
};

// Example
const threadDeletedEvent = {
  type: "threadDeleted",
  data: {
    projectId: "my-project-id",
    roomId: "my-room-id",
    threadId: "my-thread-id",
    deletedAt: "2021-10-06T01:45:56.558Z",
  },
};
```

## ThreadMetadataUpdatedEvent

An event is triggered when a thread metadata is updated. This event is not
throttled.

```ts
// Schema
type ThreadMetadataUpdatedEvent = {
  type: "threadMetadataUpdated";
  data: {
    projectId: string;
    roomId: string;
    threadId: string;
    updatedAt: string;
    updatedBy: string;
  };
};

// Example
const threadMetadataUpdatedEvent = {
  type: "threadMetadataUpdated",
  data: {
    projectId: "my-project-id",
    roomId: "my-room-id",
    threadId: "my-thread-id",
    updatedAt: "2021-10-06T01:45:56.558Z",
    updatedBy: "my-user-id",
  },
};
```

## CommentMetadataUpdatedEvent

An event is triggered when a comment’s metadata is updated. This event is not
throttled.

```ts
// Schema
type CommentMetadataUpdatedEvent = {
  type: "commentMetadataUpdated";
  data: {
    projectId: string;
    roomId: string;
    threadId: string;
    commentId: string;
    updatedAt: string;
    updatedBy: string;
  };
};

// Example
const commentMetadataUpdatedEvent = {
  type: "commentMetadataUpdated",
  data: {
    projectId: "my-project-id",
    roomId: "my-room-id",
    threadId: "my-thread-id",
    commentId: "my-comment-id",
    updatedAt: "2021-10-06T01:45:56.558Z",
    updatedBy: "my-user-id",
  },
};
```

## ThreadMarkedAsResolvedEvent

An event is triggered when a thread is marked as resolved. This event is not
throttled.

```ts
// Schema
type ThreadMarkedAsResolvedEvent = {
  type: "threadMarkedAsResolved";
  data: {
    projectId: string;
    roomId: string;
    threadId: string;
    updatedAt: string;
    updatedBy: string;
  };
};

// Example
const threadMarkedAsResolvedEvent = {
  type: "threadMarkedAsResolved",
  data: {
    projectId: "my-project-id",
    roomId: "my-room-id",
    threadId: "my-thread-id",
    updatedAt: "2021-10-06T01:45:56.558Z",
    updatedBy: "my-user-id",
  },
};
```

## ThreadMarkedAsUnresolvedEvent

An event is triggered when a thread is marked as unresolved. This event is not
throttled.

```ts
// Schema
type ThreadMarkedAsUnresolvedEvent = {
  type: "threadMarkedAsUnresolved";
  data: {
    projectId: string;
    roomId: string;
    threadId: string;
    updatedAt: string;
    updatedBy: string;
  };
};

// Example
const threadMarkedAsUnresolvedEvent = {
  type: "threadMarkedAsUnresolved",
  data: {
    projectId: "my-project-id",
    roomId: "my-room-id",
    threadId: "my-thread-id",
    updatedAt: "2021-10-06T01:45:56.558Z",
    updatedBy: "my-user-id",
  },
};
```

## NotificationEvent

Notification events are designed to help you create notification emails for your
users. By default, they’re triggered 30 minutes after an activity occurs, but
this number can be modified in your [dashboard](/dashboard) inside a project’s
settings.

This webhook event is triggered by both Liveblocks and custom notification
`kinds`, as detailed below.

### Thread notification

When using [Comments](/docs/products/comments), an event is triggered 30 minutes
after a user has been mentioned or replied to in a thread, and has not seen the
thread. It will also be triggered if the user has subscribed to the thread and
has not seen the thread. The event won’t be triggered if the user has seen the
thread or unsubscribed from the room’s thread notifications. This is the
Liveblocks `thread` notification kind.

```ts
// Schema
type ThreadNotificationEvent = {
  type: "notification";
  data: {
    channel: "email";
    kind: "thread";
    projectId: string;
    roomId: string;
    userId: string;
    threadId: string;
    inboxNotificationId: string;
    // Date representing the time when the webhook event was created.
    createdAt: string;
    // Date representing the time when the notification itself was created.
    triggeredAt: string;
  };
};

// Example
const threadNotificationEvent = {
  type: "notification",
  data: {
    channel: "email",
    kind: "thread",
    projectId: "my-project-id",
    roomId: "my-room-id",
    userId: "my-user-id",
    threadId: "my-thread-id",
    inboxNotificationId: "my-inbox-notification-id",
    createdAt: "2021-10-06T01:45:56.558Z",
    triggeredAt: "2021-10-06T01:50:56.558Z",
  },
};
```

If you want to easily identify this event in your code then you can use the type
guard
[`isThreadNotificationEvent`](/docs/api-reference/liveblocks-node#isThreadNotificationEvent).

### TextMention notification

When using [Text editor](/docs/use-cases/text-editor), an event is triggered 30
minutes after a user has been mentioned in a text and has not seen the text
mention. This is the Liveblocks `textMention` notification kind.

```ts
// Schema
type TextMentionNotificationEvent = {
  type: "notification";
  data: {
    channel: "email";
    kind: "textMention";
    projectId: string;
    roomId: string;
    userId: string;
    mentionId: string;
    inboxNotificationId: string;
    // Date representing the time when the webhook event was created.
    createdAt: string;
    // Date representing the time when the notification itself was created.
    triggeredAt: string;
  };
};

// Example
const textMentionNotificationEvent = {
  type: "notification",
  data: {
    channel: "email",
    kind: "textMention",
    projectId: "my-project-id",
    roomId: "my-room-id",
    userId: "my-user-id",
    mentionId: "my-mention-id",
    inboxNotificationId: "my-inbox-notification-id",
    createdAt: "2021-10-06T01:45:56.558Z",
    triggeredAt: "2021-10-06T01:50:56.558Z",
  },
};
```

If you want to easily identify this event in your code then you can use the type
guard
[`isTextMentionNotificationEvent`](/docs/api-reference/liveblocks-node#isTextMentionNotificationEvent).

### Custom notification

An event is triggered 30 minutes after the user has been notified of a custom
event and has not seen the notification. All custom notification `kinds` are
prefixed with `$` and are manually by you on the server. Learn more about
[triggering custom notifications](/docs/api-reference/rest-api-endpoints#post-inbox-notifications-trigger).

```ts
// Schema
type CustomNotificationEvent = {
  type: "notification";
  data: {
    channel: "email";
    kind: "$yourKind"; // Can be any string starting with "$" as defined by the user
    projectId: string;
    roomId: string | null;
    userId: string;
    inboxNotificationId: string;
    // Date representing the time when the webhook event was created.
    createdAt: string;
    // Date representing the time when the notification itself was created.
    triggeredAt: string;
  };
};

// Example
const customNotificationEvent = {
  type: "notification",
  data: {
    channel: "email",
    kind: "$fileUpload",
    projectId: "my-project-id",
    roomId: "my-room-id",
    userId: "my-user-id",
    inboxNotificationId: "my-inbox-notification-id",
    createdAt: "2021-10-06T01:45:56.558Z",
    triggeredAt: "2021-10-06T01:50:56.558Z",
  },
};
```

If you want to easily identify this event in your code then you can use the type
guard
[`isCustomNotificationEvent`](/docs/api-reference/liveblocks-node#isCustomNotificationEvent).

---

For an overview of all available documentation, see [/llms.txt](/llms.txt).
