> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sublay.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Comment

> The Comment interface shape returned by the API and SDK

A comment represents a user-authored response to an entity. Comments support nested replies, reactions, GIF attachments, user mentions, and moderation.

## Properties

| Property | Type | Description |
| - | - | - |
| `id` | `string` | Unique comment identifier (UUID). |
| `foreignId` | `string \| null` | Your system's ID for this comment, if applicable. |
| `entityId` | `string` | The entity this comment belongs to. |
| `spaceId` | `string \| null` | The space of the comment's entity. `null` when the entity isn't in a space. |
| `entity` | `CommentEntity \| null` | The entity the comment is on, as its stored record — see [The included entity](#the-included-entity) for which fields it carries. Populated when `include` contains `"entity"` or `"space"`. `null` when the entity isn't available to the caller — for example, removed by a moderator, or on [your own comment on an entity whose author blocked you](/v8/api-reference/users/fetch-comments-by-user-id#your-own-comments-on-an-unavailable-entity). The comment is still returned, and `null` doesn't say why. |
| `userId` | `string \| null` | The ID of the user who posted this comment. `null` on [placeholders](#placeholders). |
| `user` | `User \| null` | The comment author. Populated when `include` contains `"user"`. `null` on placeholders. |
| `parentId` | `string \| null` | ID of the parent comment if this is a reply. `null` for top-level comments. |
| `parentComment` | `Comment \| null` | The parent comment, under the same placeholder and block rules as any comment. Populated when `include` contains `"parent"` (user history and single-comment fetches). `null` for top-level comments, when the parent no longer exists or is on another entity, and on your own comment on an unavailable entity. |
| `referencedCommentId` | `string \| null` | ID of the comment this one quotes, set with `referencedCommentId` when the comment is created. `null` when it quotes none, or the quoted comment no longer exists. |
| `content` | `string \| null` | Text content of the comment. `null` on placeholders. |
| `gif` | `GifData \| null` | Attached GIF, if any. `null` on placeholders. |
| `mentions` | `Mention[]` | Array of user mentions embedded in the comment. `[]` on placeholders. |
| `attachments` | `Record<string, any>[]` | Generic attachment objects. `[]` on placeholders. |
| `upvotes` | `string[]` | Legacy v6 field — array of user IDs that upvoted. Use `reactionCounts` in v8. |
| `downvotes` | `string[]` | Legacy v6 field — array of user IDs that downvoted. Use `reactionCounts` in v8. |
| `reactionCounts` | `ReactionCounts` | Counts for all 8 reaction types. See [Reaction](/v8/data-models/reaction). |
| `userReaction` | `ReactionType \| null` | The current user's reaction, populated when authenticated. |
| `repliesCount` | `number` | Number of direct replies to this comment, for display. See [What `repliesCount` counts](#what-repliescount-counts). |
| `grants` | `GrantSummary \| undefined` | Per-item [reputation-grant](/v8/data-models/reputation-grant) summary — `{ total, count, viewerTotal }` over **positive** grants. Populated when `include` contains `"grants"`. Zero-filled rather than omitted on a project with no grants, so `undefined` always means "nobody asked". |
| `metadata` | `Record<string, any> \| null` | Custom key-value data, up to 10 KB (10,240 bytes) as JSON. `null` on placeholders. |
| `moderationStatus` | `"approved" \| "removed" \| null` | Space moderation status. Visible to everyone. |
| `moderatedAt` | `Date \| null` | When the moderation action was taken. |
| `moderatedById` | `string \| null` | ID of the moderator. Visible only to moderators and keys — see [Moderation fields](#moderation-fields); `null` for everyone else. |
| `moderatedByType` | `"client" \| "user" \| null` | Whether a client (admin) or user performed moderation. Visible only to moderators and keys — see [Moderation fields](#moderation-fields); `null` for everyone else. |
| `moderationReason` | `string \| null` | Reason provided for moderation. Visible only to moderators, keys and the comment's author — see [Moderation fields](#moderation-fields); `null` for everyone else. |
| `userDeletedAt` | `Date \| null` | Set when the author deletes their own comment. The comment stays in threads as a [placeholder](#placeholders), so the replies under it remain. |
| `createdAt` | `Date` | When the comment was created. |
| `updatedAt` | `Date` | When the comment was last updated. |
| `deletedAt` | `Date \| null` | Legacy field; always `null` in responses. A user-deleted comment is marked by `userDeletedAt`. |
| `parentDeletedAt` | `Date \| null` | Legacy field; always `null` in responses. |
| `isAuthorBlocked` | `boolean` | `true` when the requesting user blocked this comment's author and the comment is returned in full. See [Blocked authors](#blocked-authors). |
| `isUnavailable` | `boolean` | `true` when the comment exists but can't be shown to the requesting user; it is returned as a placeholder. See [Blocked authors](#blocked-authors). |
| `replies` | `{ data: Comment[]; pagination: { nextCursor: string \| null; hasMore: boolean } }` | Nested replies. Present only on [thread fetches](/v8/api-reference/comments/fetch-many-comments#nested-replies) with `replyDepth` above `0`, and absent on comments at the last nested level. |

## Nested Types

### GifData

| Property | Type | Description |
| - | - | - |
| `id` | `string` | GIF provider identifier. |
| `url` | `string` | URL to the GIF page or canonical source. |
| `gifUrl` | `string` | Direct URL to the animated GIF file. |
| `gifPreviewUrl` | `string` | URL to a lower-quality preview of the GIF. |
| `altText` | `string` | Accessible description of the GIF. Required. |
| `aspectRatio` | `string` | Width-to-height ratio for rendering, as a string — e.g. `"1.5"`, not `1.5`. |

All six fields are required when a GIF is attached.

## Includes

Pass `include` to populate optional fields. What each endpoint accepts:

| Include value | Populates | Thread fetch | User history and single-comment fetches |
| - | - | :-: | :-: |
| `"user"` | `user` — the comment author | ✓ | ✓ |
| `"grants"` | `grants` — the reputation-grant summary | ✓ | ✓ |
| `"entity"` | `entity` — the entity the comment is on | | ✓ |
| `"space"` | `entity` with its `space` populated | | ✓ |
| `"parent"` | `parentComment` — the parent comment, for replies | | ✓ |

On a thread fetch, `include` applies at every nested level.

### The included entity

`entity` is the entity's stored record. It carries every stored [Entity](/v8/data-models/entity) field — `id`, `shortId`, `foreignId`, `sourceId`, `spaceId`, `userId`, `title`, `content`, `mentions`, `attachments`, `keywords`, `upvotes`, `downvotes`, `reactionCounts`, `sharesCount`, `views`, `score`, `scoreUpdatedAt`, `location`, `metadata`, `nsfw`, the moderation fields, `isDraft`, `createdAt`, `updatedAt` and `deletedAt`.

The fields an entity fetch computes or joins are **not included**:

| Not included | What to use instead |
| - | - |
| `commentsCount` | Fetch the entity. |
| `userReaction` | Fetch the entity. |
| `nsfwEffective` | `entity.nsfw`, combined with `entity.space.nsfwEffective` when `include` contains `"space"`. |
| `user` | `entity.userId`, or fetch the entity with `include=user`. |
| `files` | Fetch the entity with `include=files`. |
| `topComments` | Fetch the entity with `include=topComments`. |
| `isSaved` | Fetch the entity with `include=saved`. |
| `grants` | Fetch the entity with `include=grants`. The comment's own `grants` is unaffected. |

`entity.space` is present only when `include` contains `"space"`, and is `null` when the entity isn't in a space. It is the [Space](/v8/data-models/space) record with `membersCount` and `childSpacesCount` (and `isMember` for a signed-in caller), without the `avatarFile` and `bannerFile` objects.

## Placeholders

A comment that can't be shown in full stays in place as a **placeholder**, so the replies under it — other people's conversation — aren't lost. There are three kinds, and each keeps a marker so your app can tell them apart:

| Kind | Marker | Who sees the full comment |
| - | - | - |
| Deleted by its author | `userDeletedAt` is set | Nobody |
| Removed by a moderator | `moderationStatus: "removed"` | Its author |
| Unavailable to this user | `isUnavailable: true` | — |

On a placeholder, `userId`, `user`, `content`, `gif` and `metadata` are `null`, and `mentions` and `attachments` are `[]`. Everything else is kept: `id`, `entityId`, `parentId`, `foreignId`, timestamps, `reactionCounts`, `repliesCount` and the markers.

Markers can combine — for example, a deleted comment whose author blocked the requesting user carries both `userDeletedAt` and `isUnavailable: true`. Render `isUnavailable` first: show the neutral unavailable row, without reply or reaction controls.

Nothing is written into `content`; render your own wording for each kind.

A deleted or removed comment can't take new direct replies, new reactions or quotes — including a removed comment its author sees in full — so hide the reply, reaction and quote controls on it. The replies already under it can still be replied to, and a reaction already on it can still be [removed](/v8/api-reference/comments/remove-reaction). See [Deleted and removed parents and quotes](/v8/api-reference/comments/create-comment#deleted-and-removed-parents-and-quotes) and [Add Comment Reaction](/v8/api-reference/comments/add-reaction#deleted-and-removed-comments).

A placeholder's moderation fields follow [Moderation fields](#moderation-fields): `moderationStatus` is always kept, and `moderationReason`, `moderatedById` and `moderatedByType` are filled only for the requesters listed there.

## Moderation fields

`moderationStatus` is returned to everyone. The other three moderation fields are returned only to some requesters, on every comment response; everyone else gets `null`:

| Requester | `moderationReason` | `moderatedById`, `moderatedByType` |
| - | - | - |
| An active admin or moderator of the comment's space | ✓ | ✓ |
| A user whose project [`role`](/v8/data-models/user) is `admin` or `moderator` | ✓ | ✓ |
| A request made with a service or master key | ✓ | ✓ |
| The comment's author | ✓ | — |
| Anyone else, including signed-out requests | — | — |

A comment on an entity with no space has no space moderators: only project-role admins and moderators, keys and the comment's author qualify.

## Blocked authors

When the requesting user is signed in and the `moderation` bundle is installed, comments returned by thread, user-history, single-comment, `topComments`, update-comment and add/remove-reaction responses carry two flags (both `false` by default):

| The requesting user and the comment's author | The comment is returned as | Flags |
| - | - | - |
| The requesting user blocked the author | the full comment | `isAuthorBlocked: true` |
| The author blocked the requesting user, or both blocked each other | a placeholder | `isUnavailable: true`, `isAuthorBlocked: false` |
| No block | usual | both `false` |

* **`isAuthorBlocked`** reflects only the requesting user's own preference. Your app decides how to render it — collapse it, offer "show anyway", or hide it. The user can still reply to and react to it.
* **`isUnavailable`** is neutral: the comment exists, but can't be shown to this user, and the reason isn't disclosed. Replying to or reacting to it is refused, so hide those controls.

The other responses that return a comment — create comment and search — don't include these flags.

## What `repliesCount` counts

`repliesCount` is the number of a comment's direct replies, and it counts **everything the thread contains**: deleted, removed and unavailable replies included, since they stay in the thread as placeholders. It's the same number for every user, and it matches what paging through the comment's replies returns. Use it for display ("12 replies"), and use `pagination.hasMore` to decide whether to show a "load more" button.

An entity's [`commentsCount`](/v8/data-models/entity) counts its comments at every depth by the same rule.

## See Also

* [Reaction](/v8/data-models/reaction)
* [Entity](/v8/data-models/entity)
* [ReputationGrant](/v8/data-models/reputation-grant)
* [Fetch Many Comments](/v8/api-reference/comments/fetch-many-comments)
* [Fetch Comments by User](/v8/api-reference/users/fetch-comments-by-user-id)
* [useEntityComments hook](/v8/hooks/comments/use-entity-comments)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.