Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion docs/pages/api-reference/liveblocks-client.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -3563,7 +3563,20 @@ const body: CommentBody = {
#### Defining comment metadata [#defining-comment-metadata]

Custom metadata can be attached to each comment. `string`, `number`, and
`boolean` properties are allowed.
`boolean` properties are allowed. First, type your data with `CommentMetadata`.

```ts file="liveblocks.config.ts"
declare global {
interface Liveblocks {
CommentMetadata: {
priority: number;
reviewed: boolean;
};
}
}
```

Then use it in your code.

```ts
const metadata: Liveblocks["CommentMetadata"] = {
Expand Down
1 change: 1 addition & 0 deletions docs/pages/api-reference/liveblocks-react-lexical.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -1093,6 +1093,7 @@ import { Composer } from "@liveblocks/react-ui/primitives";
body: comment.body,
attachments: comment.attachments,
metadata: ...,
commentMetadata: ...,
});

editor.dispatchCommand(ATTACH_THREAD_COMMAND, thread.id);
Expand Down
1 change: 1 addition & 0 deletions docs/pages/api-reference/liveblocks-react-tiptap.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -1017,6 +1017,7 @@ import { Composer } from "@liveblocks/react-ui/primitives";
body: comment.body,
attachments: comment.attachments,
metadata: ...,
commentMetadata: ...,
});

editor.commands.addComment(thread.id);
Expand Down
132 changes: 131 additions & 1 deletion docs/pages/api-reference/liveblocks-react-ui.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -1045,6 +1045,121 @@ import { Comment, Thread } from "@liveblocks/react-ui";
/>;
```

##### Rendering custom components

You can render fully custom components in comment threads, instead of showing
the default `Comment` component. This is particularly useful for inserting
custom UI into threads, such as data visualizations, tables,
[custom AI commenting components](/docs/get-started/nextjs-comments-ai), and
more.

Picture a thread that features a graph visualization instead of a comment. To
render it in the thread, you can create a comment and use its
[comment metadata](/docs/ready-made-features/comments/metadata) to define its
data. First, set up your metadata typing in your config file. We鈥檒l define two
types of comments, a normal comment and a graph comment, and pass both to
`CommentMetadata`. Any data can go in here, but in this example, graphs are
defined with `type: "graph"` and a `graphId`.

```ts file="liveblocks.config.ts"
type NormalComment = {};

// +++
type GraphComment = {
type: "graph";
graphId: string;
};
// +++

declare global {
interface Liveblocks {
// +++
CommentMetadata: NormalComment | GraphComment;
// +++
}
}
```

Next, create the comment. This comment will most likely by created on the
server, using
[`liveblocks.createComment`](/docs/api-reference/liveblocks-node#post-rooms-roomId-threads-threadId-comments).
Set your graph鈥檚 metadata in the comment鈥檚 `metadata` option.

```ts
const comment = await liveblocks.createComment({
roomId: "my-room-id",
threadId: "th_d75sF3...",
data: {
body: {
version: 1,
content: [
{ type: "paragraph", children: [{ text: "Graph placeholder" }] },
],
},
userId: "bot@example.com",
},
// +++
metadata: {
type: "graph",
graphId: "revenue-by-month",
},
// +++
});
```

To render this graph inside a comment thread, check for the `type: "graph"`
value you defined in `comment.metadata`, and return a custom component instead
of a `Comment`. Make sure to return `Comment` for all regular comments.

```tsx
import { Comment, Thread } from "@liveblocks/react-ui";

<Thread
thread={thread}
components={{
Comment: ({ comment, ...props }) => {
// Render your custom graph inside a comment UI
// +++
if (comment.metadata?.type === "graph") {
return <Graph graphId={comment.metadata.graphId} />;
}
// +++

return <Comment comment={comment} {...props} />;
},
}}
/>;
```

If you鈥檇 like to render a custom component _inside_ a comment UI, for example
with avatar, author, date, then
[customize the comment component](#Customize-comments) instead of returning a
fully custom component.

```tsx
import { Comment, Thread } from "@liveblocks/react-ui";

<Thread
thread={thread}
components={{
Comment: ({ comment, ...props }) => {
// Render your custom graph component
// +++
if (comment.metadata?.type === "graph") {
return (
<Comment comment={comment} {...props}>
<Graph graphId={comment.metadata.graphId} />
</Comment>
);
}
// +++

return <Comment comment={comment} {...props} />;
},
}}
/>;
```

##### Customize dropdown items

`Thread` shows a dropdown menu for threads and comments which contains actions
Expand Down Expand Up @@ -1506,7 +1621,19 @@ function Component({ threadId }) {
##### Adding comment metadata

If you鈥檇 like to attach custom metadata to a reply, you can add a
`commentMetadata` prop.
`commentMetadata` prop. This prop is typed as `CommentMetadata`.

```ts file="liveblocks.config.ts"
declare global {
interface Liveblocks {
CommentMetadata: {
tag?: string;
spam: boolean;
slackMessageTs: string;
};
}
}
```

```tsx
import { Composer } from "@liveblocks/react-ui";
Expand Down Expand Up @@ -2204,6 +2331,7 @@ function MyComposer() {
body,
attachments,
metadata: {},
commentMetadata: {},
});
// +++
}
Expand Down Expand Up @@ -3154,6 +3282,7 @@ function MyComposer() {
body,
attachments,
metadata: {},
commentMetadata: {},
});
}}
>
Expand Down Expand Up @@ -3201,6 +3330,7 @@ function MyComposer() {
body,
attachments,
metadata: {},
commentMetadata: {},
});
}}
>
Expand Down
28 changes: 26 additions & 2 deletions docs/pages/api-reference/liveblocks-react.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -2629,6 +2629,13 @@ type Storage = {
// quote: string;
// time: number;
// };
//
// Optionally, when using Comments, CommentMetadata represents metadata on
// each thread. Can only contain booleans, strings, and numbers.
// export type CommentMetadata = {
// tag: string;
// spam: boolean;
// };

export const {
RoomProvider,
Expand All @@ -2640,7 +2647,7 @@ export const {
} = createRoomContext<
Presence,
Storage
/* UserMeta, RoomEvent, ThreadMetadata */
/* UserMeta, RoomEvent, ThreadMetadata, CommentMetadata */
>(client);
```

Expand Down Expand Up @@ -6726,6 +6733,9 @@ declare global {
// Custom metadata set on threads, for useThreads, useCreateThread, etc.
ThreadMetadata: {};

// Custom metadata set on comments, for useCreateThread, useCreateComment, etc.
CommentMetadata: {};

// Custom room info set with resolveRoomsInfo, for useRoomInfo
RoomInfo: {};

Expand Down Expand Up @@ -6781,6 +6791,13 @@ declare global {
y: number;
};

// Custom metadata set on comments, for useCreateThread, useCreateComment, etc.
CommentMetadata: {
// Example, attaching a tag and a spam flag to a comment
tag: string;
spam: boolean;
};

// Custom room info set with resolveRoomsInfo, for useRoomInfo
RoomInfo: {
// Example, rooms with a title and url
Expand Down Expand Up @@ -6864,6 +6881,13 @@ type Storage = {
// quote: string;
// time: number;
// };
//
// CommentMetadata represents metadata on each comment. Can only contain
// booleans, strings, and numbers.
// export type CommentMetadata = {
// tag: string;
// spam: boolean;
// };

export const {
RoomProvider,
Expand All @@ -6875,7 +6899,7 @@ export const {
} = createRoomContext<
Presence,
Storage
/* UserMeta, RoomEvent, ThreadMetadata */
/* UserMeta, RoomEvent, ThreadMetadata, CommentMetadata */
>(client);
```

Expand Down
54 changes: 37 additions & 17 deletions docs/pages/pricing/billing.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,30 @@ meta:
description: "How billing works on Liveblocks, from credits to your invoice."
---

This page explains how credits, billing cycles, overage, and invoices work. For
plan prices and metered rates, see [Pricing overview](/docs/pricing/overview).
Understand how your bill is calculated: monthly credits, overage, annual
billing, invoices, and tracking your usage. For plan prices and metered rates,
see [Plans](/docs/pricing/plans).

## Credits

Every paid plan includes a monthly credit allowance. Credits are applied
automatically to your metered usage, like realtime collaboration minutes,
comments, custom notifications, and storage. You only pay once you have used up
your credits. Your plan base is what buys those credits, and on higher Team
tiers the included credits are worth more than the base price, so you get more
usage for the same spend.
Every plan includes a monthly credit allowance that covers your metered usage
first. Credits are denominated in US dollars. If your usage exceeds the amount
of credits in your base plan, you'll be billed at the per-unit rates at the end
of the month. Credits reset at the start of each billing cycle and do not roll
over.

The Team plan offers multiple credit packages that include more credit value
than they cost, effectively lowering your per credit rate.

### Team plan options

| Monthly credits | Monthly price | Annual price |
| ---------------------------------------- | -------------------------------------------------------- | ------------------------------------------------------------------------ |
| <Limits.TeamAnnualCredits tier={600} /> | <Limits.TeamMonthlyPriceForTier tier={600} /> per month | <Limits.TeamAnnualPricePerMonth tier={600} /> per month billed annually |
| <Limits.TeamAnnualCredits tier={900} /> | <Limits.TeamMonthlyPriceForTier tier={900} /> per month | <Limits.TeamAnnualPricePerMonth tier={900} /> per month billed annually |
| <Limits.TeamAnnualCredits tier={1500} /> | <Limits.TeamMonthlyPriceForTier tier={1500} /> per month | <Limits.TeamAnnualPricePerMonth tier={1500} /> per month billed annually |
| <Limits.TeamAnnualCredits tier={2250} /> | <Limits.TeamMonthlyPriceForTier tier={2250} /> per month | <Limits.TeamAnnualPricePerMonth tier={2250} /> per month billed annually |
| <Limits.TeamAnnualCredits tier={3750} /> | <Limits.TeamMonthlyPriceForTier tier={3750} /> per month | <Limits.TeamAnnualPricePerMonth tier={3750} /> per month billed annually |

## Billing cycle

Expand All @@ -24,9 +37,16 @@ at the start of each cycle and do not roll over.

## Overage

Usage above your monthly credits is overage. It is charged at the per-unit rates
in each plan's [Metered usage](/docs/pricing/plans/pro#Metered-usage) table and
added to your invoice. Your total is always your plan base plus any overage.
Usage above your monthly credits is overage. If your usage exceeds the amount of
credits in your base plan, you'll be billed at the
[per-unit rates](/docs/pricing/plans#Metered-usage) at the end of the month.

## Free plan usage

Even though the Free plan has no cost, usage follows the same monthly cycle. If
your account exceeds a limit, the affected feature pauses until limits reset at
the start of the next calendar month or you
[upgrade your account](/dashboard/billing) to a paid plan.

## Annual billing

Expand All @@ -36,11 +56,11 @@ reset each month.
## Invoices and payment

Paid plans are billed by card. Invoicing is available on Enterprise.
[Contact sales](/contact/sales) to set this up. You can view and download past
invoices from your [dashboard billing settings](/dashboard).
[Contact sales](/contact/sales) to discuss upgrading to an Enterprise plan.

You can view and download past invoices from your [dashboard](/dashboard).

## Tracking your spend
## Tracking your usage

See your usage and remaining credits at any time on your
[dashboard usage page](/dashboard/usage), so there are no surprises on your
invoice.
Usage and remaining credits are accessible to all account Owners in the
[Liveblocks dashboard](/dashboard/usage).
Loading
Loading