With Liveblocks 1.9, we’re updating Comments, introducing a way to
programmatically create and modify threads, comments, and reactions. This
enables a number of different use cases such as AI agents, moderation, and
two-way synchronization with messaging apps. We’re also adding a way to filter
threads by metadata.

- [Modifying comments programmatically](#modifying-comments-programmatically)
- [AI agents, moderation, and more](#ai-agents-moderation-and-more)
- [Thread filtering](#thread-filtering)

## Upgrade now [#upgrade-now]

Start using the new features now by updating each Liveblocks package in your
project to the `@latest` version.

```bash
 npm install @liveblocks/client@latest @liveblocks/react@latest @liveblocks/react-comments@latest liveblocks/node@latest
```

Note that there’s a small **breaking change**—all dates returned from Comments
are now `Date` objects instead of `strings`.

```tsx
// ❌ Before - "2023-12-15T14:15:22Z"
console.log(comment.createdAt);

// ✅ After - Date <Fri Dec 15 2023 14:15:22 GMT+0000 (Greenwich Mean Time)>
console.log(comment.createdAt);
```

Learn more in our [upgrade guide](/docs/platform/upgrading/1.9).

## Modifying comments programmatically [#modifying-comments-programmatically]

It’s now possible to create and modify comments, threads, and reactions,
programmatically using the typed REST API functions in `@liveblocks/node`. There
are seven new functions—here’s a few examples.

```ts
// Create a new thread
const thread = await liveblocks.createThread({
  roomId: "my-room-id",
  data: {
    /* ... */
  },
});

// Edit a thread's metadata
const editedMetadata = await liveblocks.editThreadMetadata({
  roomId: "my-room-id",
  threadId: "th_d75sF3...",
  data: {
    /* ... */
  },
});

// Delete a comment
await liveblocks.deleteComment({
  roomId: "my-room-id",
  threadId: "th_d75sF3...",
  commentId: "cm_agH76a...",
});
```

If you’re not using JavaScript, you can also call our
[REST API](/docs/api-reference/rest-api-endpoints#Comments) directly to modify
comments.

```bash
curl -X DELETE "https://api.liveblocks.io/v2/rooms/my-room-id/threads/th_d75sF3.../comments/cm_agH76a..."
```

You can find more information in the API reference for each new function.

- [`createThread`](/docs/api-reference/liveblocks-node#post-rooms-roomId-threads)
- [`editThreadMetadata`](/docs/api-reference/liveblocks-node#post-rooms-roomId-threads-threadId-metadata)
- [`createComment`](/docs/api-reference/liveblocks-node#post-rooms-roomId-threads-threadId-comments)
- [`editComment`](/docs/api-reference/liveblocks-node#post-rooms-roomId-threads-threadId-comments-commentId)
- [`deleteComment`](/docs/api-reference/liveblocks-node#delete-rooms-roomId-threads-threadId-comments-commentId)
- [`addCommentReaction`](/docs/api-reference/liveblocks-node#post-rooms-roomId-threads-threadId-comments-commentId-add-reaction)
- [`removeCommentReaction`](/docs/api-reference/liveblocks-node#post-rooms-roomId-threads-threadId-comments-commentId-remove-reaction)

## AI agents, moderation, and more [#ai-agents-moderation-and-more]

The ability to programmatically modify comments enables a host of new
possibilities, such as AI agents, comment moderation, and two-way chat
synchronization.

### AI agents

Using webhooks, you can now create an AI agent that responds to comments, such
as in [our example using GPT4](/examples/ai-comments/nextjs-comments-ai).

<Figure>
  <figcaption className="sr-only">
    A user asking an AI agent a question by tagging "@Liveblocks AI", with the
    agent responding shortly after.
  </figcaption>
  <video autoPlay loop muted playsInline>
    <source
      src="/images/blog/liveblocks-1-9/comments-ai-agent.mp4"
      type="video/mp4"
    />
  </video>
</Figure>

This example uses the
[`CommentCreated`](/docs/platform/webhooks#CommentCreatedEvent) webhook event in
combination with
[`liveblocks.createComment`](/docs/api-reference/liveblocks-node#post-rooms-roomId-threads-threadId-comments).

### Comment moderation

If we take programmatically modifying comments to the next level, we can
implement various types of comment moderation, such as banned word filtering, or
creating moderator users.

<Figure highlight={false}>
  <Image
    src="/images/blog/liveblocks-1-9/delete-comment.png"
    alt=""
    width={820}
    height={394}
    quality={90}
  />
</Figure>

When using Comments React hooks, such as
[`useDeleteComment`](/docs/api-reference/liveblocks-react#useDeleteComment), you
can only delete _your own_ comments. However, because the new APIs runs server
side, requiring your secret key, you can use them to delete _any user’s_
comments. Here’s an example of a server action that does exactly this.

```tsx
// A button that can delete a comment written by any user
function DeleteButton({ roomId, threadId, commentId }) {
  async function deleteComment() {
    "use server";
    await liveblocks.deleteComment({ roomId, threadId, commentId });
  }

  return (
    <form action={deleteComment}>
      <button type="submit">Delete comment</button>
    </form>
  );
}
```

This code snippet is using
[`liveblocks.deleteComment`](/docs/api-reference/liveblocks-react#useDeleteComment).

### Two-way messaging synchronization

Another use for our new APIs is bi-directional synchronization, the ability to
send and receive updates between Comments and another service. This means it’s
now possible to mirror a chat application, and have messages automatically
synchronize.

<Figure highlight={false}>
  <Image
    src="/images/blog/liveblocks-1-9/synchronization.png"
    alt=""
    width={820}
    height={394}
    quality={90}
  />
</Figure>

Here’s an example of an endpoint that receives a new thread from a messaging
application, then copies it to Comments—the first direction necessary in two-way
synchronization.

```ts
// Endpoint that receives a new thread from a chat application
export async function POST(request: Request) {
  const { message, userId, roomId, threadId } = await request.json();
  const commentBody = __formatComment__(message);

  // Create the chat thread in Comments
  await liveblocks.createThread({
    roomId,
    data: {
      comment: {
        userId,
        body: commentBody,
      },
    },
  });
}
```

Then in the other direction, you can listen for threads posted to Comments with
webhook events, and copy the thread into your messaging app.

```ts
// Endpoint that receives `threadCreated` webhook events
export async function POST(request: Request) {
  // Verify your webhook request and get `event`
  // ...

  const { roomId, threadId } = event.data;
  const thread = await liveblocks.getThread({ roomId, threadId });
  const message = await stringifyCommentBody(thread.comments[0].body);

  // Send new thread to messaging app
  await __sendThread__({ roomId, threadId, message });
}
```

This uses the [`CommentCreated`](/docs/platform/webhooks#CommentCreatedEvent)
webhook event in combination with
[`liveblocks.createComment`](/docs/api-reference/liveblocks-node#post-rooms-roomId-threads-threadId-comments).

## Thread filtering [#thread-filtering]

In Liveblocks 1.9
[`useThreads`](/docs/api-reference/liveblocks-react#useThreads) now has a query
option, allowing you to filter threads by metadata.

```tsx
// Fetch threads with `metadata.resolved === true`
const threads = useThreads({
  query: {
    metadata: {
      resolved: true,
    },
  },
});
```

When multiple metadata fields are passed, the logical `AND` operator is used,
returning a list of threads with every property.

```tsx
// Threads with `metadata.resolved === true` AND `metadata.color === "red"`
const threads = useThreads({
  query: {
    metadata: {
      resolved: true,
      color: "red",
    },
  },
});
```

## Upgrade guide

Remember there’s a change to the way dates are handled in this update, so make
sure to check the [upgrade guide](/docs/platform/upgrading/1.9) to learn more.

```tsx
// ❌ Before - "2023-12-15T14:15:22Z"
console.log(comment.createdAt);

// ✅ After - Date <Fri Dec 15 2023 14:15:22 GMT+0000 (Greenwich Mean Time)>
console.log(comment.createdAt);
```

## Get started with Comments

If you’d like to add Comments to your application, make sure to check out our
guides and examples.

- [Get started with Comments](/docs/get-started/nextjs-comments)
- [Comments examples](/examples/browse/comments)
- [Comments guides](/docs/guides?topics=comments)

## Contributors

Huge thanks to everyone who contributed and specifically to
[Florent Lefebvre](https://twitter.com/florentpml),
[Nimesh Nayaju](https://twitter.com/nayajunimesh),
[Olivier Foucherot](https://www.linkedin.com/in/olivier-foucherot),
[Guillaume Salles](https://twitter.com/guillaume_slls), for all their work on
this update. Keep checking out the
[changelog](https://github.com/liveblocks/liveblocks/blob/main/CHANGELOG.md) for
the full release notes–see you next time!