---
url: https://talkjs.com/docs/Data_APIs/JavaScript/Message_Content
title: 'Message content'
minidoc-source: js
minidoc-lib: data-api
---

Every message has "content" which specifies the information in the message.
This could be some formatted text, a file attachment, or a shared location.

See the [conceptual documentation](/Concepts/Message_Content/) for message 
content to learn more about how TalkJS represents message content.

## ContentBlock
/** The content of a message is structured as a list of content blocks.
Currently, each message can only have one content block, but this will change in the future. This will not be considered a breaking change, so your code should assume there can be multiple content blocks.
These blocks are rendered in order, top-to-bottom.
Currently the available Content Block types are:
- `type: "text"` (TextBlock)
- `type: "file"` (FileBlock)
- `type: "location"` (LocationBlock) */
export type ContentBlock = TextBlock|FileBlock|LocationBlock;

## TextBlock
/** A block of formatted text in a message's content.
Each TextBlock is a tree of TextNode children describing the structure of some formatted text. Each child is either a plain text string, or a `node` representing some text with additional formatting.
For example, if the user typed:>*This first bit* is bold, and *_the second bit_* is bold and italics
Then this would become a Text Block with the structure:
```json
{
type: "text",
children: [
{
type: "text",
children: [
{ type: "bold", children: ["This first bit"] },
" is bold, and ",
{
children: [
{ type: "italic", children: ["the second bit"] }
],
type: "bold",
},
" is bold and italics",
],
},
],
}
```
Rather than relying on the automatic message parsing, you can also specify the `TextBlock` directly using ConversationRef.send with SendMessageParams. */
export interface TextBlock  {
readonly children: TextNode[];
readonly type: "text";
}

## TextNode
/** Any node that can exist inside a TextBlock.
The simplest `TextNode` is a plain text string. Using "hello" as an example message, the `TextBlock` would be:
```ts
{
type: 'text';
children: ['hello'];
}
```
Other than plain text, there are many different kinds of node which render some text in a specific way or with certain formatting.
```ts
type TextNode =|string|MarkupNode|BulletListNode|BulletPointNode|CodeSpanNode|LinkNode|AutoLinkNode|ActionLinkNode|ActionButtonNode|CustomEmojiNode|MentionNode;
```
If the text node is not a plain string, it will have a `type` field indicating what kind of node it is, and either a property `text: string` or a property `children: TextNode[]`. This will be true for all nodes added in the future as well. */
export type TextNode = string|MarkupNode|BulletListNode|BulletPointNode|CodeSpanNode|LinkNode|AutoLinkNode|ActionLinkNode|ActionButtonNode|CustomEmojiNode|MentionNode;

<Callout>
<details style={{margin: "1rem"}}>
  <summary className="font-bold cursor-pointer">Full documentation of each TextNode variant</summary>

  

## MarkupNode
/** A node in a TextBlock that renders its children with a specific style. */
export interface MarkupNode  {
readonly children: TextNode[];
/** The kind of formatting to apply when rendering the children
- `type: "bold"` is used when users type `*text*` and is rendered with HTML `<strong>`
- `type: "italic"` is used when users type `_text_` and is rendered with HTML `<em>`
- `type: "strikethrough"` is used when users type `~text~` and is rendered with HTML `<s>` */
readonly type: "bold"|"italic"|"strikethrough";
}
  

## BulletListNode
/** A node in a TextBlock that adds indentation for a bullet-point list around its children (HTML `<ul>`).
Used when users send a bullet-point list by starting lines of their message with `-` or `*`. */
export interface BulletListNode  {
readonly children: TextNode[];
readonly type: "bulletList";
}
  

## BulletPointNode
/** A node in a TextBlock that renders its children with a bullet-point (HTML `<li>`).
Used when users start a line of their message with `-` or `*`. */
export interface BulletPointNode  {
readonly children: TextNode[];
readonly type: "bulletPoint";
}
  

## LinkNode
/** A node in a TextBlock that renders its children as a clickable link (HTML `<a>`).
By default, users do not have permission to send messages containing `LinkNode` as it can be used to maliciously hide the true destination of a link. */
export interface LinkNode  {
readonly children: TextNode[];
readonly type: "link";
/** The URL to open when the node is clicked. */
readonly url: string;
}
  

## AutoLinkNode
/** A node in a TextBlock that renders `text` as a link (HTML `<a>`).
Used when user-typed text is turned into a link automatically.
Unlike LinkNode, users do have permission to send AutoLinkNodes by default, because the `text` and `url` properties must match. Specifically:
- If `text` is an email, `url` must contain a `mailto:` link to the same email address
- If `text` is a phone number, `url` must contain a `tel:` link to the same phone number
- If `text` is a website, the domain name including subdomains must be the same in both `text` and `url`. If `text` includes a protocol (such as `https`), path (/page), query string (?page=true), or url fragment (#title), they must be the same in `url`. If `text` does not specify a protocol, `url` must use either `https` or `http`.
This means that the following AutoLink is valid:
```json
{
type: "autoLink",
text: "talkjs.com"
url: "/docs/JavaScript_Data_API/Message_Content/#AutoLinkNode"
}
```
That link will appear as `talkjs.com` and link you to the specific section of the documentation that explains how AutoLinkNodes work.
These rules ensure that the user knows what link they are clicking, and prevents AutoLinkNode being used for phishing. If you try to send a message containing an AutoLink that breaks these rules, the request will be rejected. */
export interface AutoLinkNode  {
/** The text to display in the link. */
readonly text: string;
readonly type: "autoLink";
/** The URL to open when a user clicks this node. */
readonly url: string;
}
  

## ActionLinkNode
/** A node in a TextBlock that renders its children as a clickable action link which triggers a custom action.
By default, users do not have permission to send messages containing `ActionLinkNode` as it can be used maliciously to trick others into invoking custom actions. For example, a user could send an "accept offer" action link, but disguise it as a link to a website. */
export interface ActionLinkNode  {
/** The name of the custom action to invoke when the link is clicked. */
readonly action: string;
readonly children: TextNode[];
/** The parameters to pass to the custom action when the link is clicked. */
readonly params: Record<string, string>;
readonly type: "actionLink";
}
  

## ActionButtonNode
/** A node in a TextBlock that renders its children as a clickable action button which triggers a custom action.
By default, users do not have permission to send messages containing action buttons as they can be used maliciously to trick others into invoking custom actions. For example, a user could send an "accept offer" action button, but disguise it as "view offer". */
export interface ActionButtonNode  {
/** The name of the custom action to invoke when the button is clicked. */
readonly action: string;
readonly children: TextNode[];
/** The parameters to pass to the custom action when the button is clicked. */
readonly params: Record<string, string>;
readonly type: "actionButton";
}
  

## CodeSpanNode
/** A node in a TextBlock that renders `text` in an inline code span (HTML `<code>`).
Used when a user types ```text```. */
export interface CodeSpanNode  {
readonly text: string;
readonly type: "codeSpan";
}
  

## CustomEmojiNode
/** A node in a TextBlock that is used for custom emoji. */
export interface CustomEmojiNode  {
/** The name (including colons at the start and end) of the custom emoji to show. */
readonly text: string;
readonly type: "customEmoji";
}
  

## MentionNode
/** A node in a TextBlock that is used when a user is mentioned.
Used when a user types `@name` and selects the user they want to mention. */
export interface MentionNode  {
/** The ID of the user who is mentioned. */
readonly id: string;
/** The name of the user who is mentioned. */
readonly text: string;
readonly type: "mention";
}
</details>
</Callout>

## FileBlock
/** A file attachment received in a message's content.
All `FileBlock` variants contain `url`, `size`, and `fileToken`. Some file blocks have additional metadata, in which case they will have the `subtype` property set.
Currently the available FileBlock subtypes are:
- No `subtype` set (GenericFileBlock)
- `subtype: "video"` (VideoBlock)
- `subtype: "image"` (ImageBlock)
- `subtype: "audio"` (AudioBlock)
- `subtype: "voice"` (VoiceBlock) */
export type FileBlock = VideoBlock|ImageBlock|AudioBlock|VoiceBlock|GenericFileBlock;

<Callout>
<details style={{margin: "1rem"}}>
  <summary className="font-bold cursor-pointer">Full documentation of each FileBlock variant</summary>

  

## GenericFileBlock
/** The most basic FileBlock variant, used whenever there is no additional metadata for a file.
Do not try to check for `subtype === undefined` directly, as this will break when we add new FileBlock variants in the future.
Instead, treat GenericFileBlock as the default. For example:
```ts
if (block.subtype === "video") {
handleVideoBlock(block);
} else if (block.subtype === "image") {
handleImageBlock(block);
} else if (block.subtype === "audio") {
handleAudioBlock(block);
} else if (block.subtype === "voice") {
handleVoiceBlock(block);
} else {
handleGenericFileBlock(block);
}
``` */
export interface GenericFileBlock  {
/** The name of the file, including file extension */
readonly filename: string;
/** An encoded identifier for this file. Use in SendFileBlock to send this file in another message. */
readonly fileToken: FileToken;
/** The size of the file in bytes */
readonly size: number;
/** Never set for generic file blocks. */
readonly subtype?: never;
readonly type: "file";
/** The URL where you can fetch the file */
readonly url: string;
}
  

## VideoBlock
/** A FileBlock variant for a video attachment, with additional video-specific metadata.
You can identify this variant by checking for `subtype: "video"`.
Includes metadata about the height and width of the video in pixels, and the duration of the video in seconds, where available.
Videos that you upload with the TalkJS UI will include the dimensions and duration as long as the sender's browser can preview the file. Videos that you upload with the REST API or Session.uploadVideo will include this metadata if you specified it when uploading. Videos attached in a reply to an email notification will not include any metadata. */
export interface VideoBlock  {
/** The duration of the video in seconds, if known. */
readonly duration?: number;
/** The name of the video file, including file extension. */
readonly filename: string;
/** An encoded identifier for this file. Use in SendFileBlock to send this video in another message. */
readonly fileToken: FileToken;
/** The height of the video in pixels, if known. */
readonly height?: number;
/** The size of the file in bytes. */
readonly size: number;
readonly subtype: "video";
readonly type: "file";
/** The URL where you can fetch the file. */
readonly url: string;
/** The width of the video in pixels, if known. */
readonly width?: number;
}
  

## ImageBlock
/** A FileBlock variant for an image attachment, with additional image-specific metadata.
You can identify this variant by checking for `subtype: "image"`.
Includes metadata about the height and width of the image in pixels, where available.
Images that you upload with the TalkJS UI will include the image dimensions as long as the sender's browser can preview the file. Images that you upload with the REST API or Session.uploadImage will include the dimensions if you specified them when uploading. Image attached in a reply to an email notification will not include the dimensions. */
export interface ImageBlock  {
/** The name of the image file, including file extension. */
readonly filename: string;
/** An encoded identifier for this file. Use in SendFileBlock to send this image in another message. */
readonly fileToken: FileToken;
/** The height of the image in pixels, if known. */
readonly height?: number;
/** The size of the file in bytes. */
readonly size: number;
readonly subtype: "image";
readonly type: "file";
/** The URL where you can fetch the file. */
readonly url: string;
/** The width of the image in pixels, if known. */
readonly width?: number;
}
  

## AudioBlock
/** A FileBlock variant for an audio attachment, with additional audio-specific metadata.
You can identify this variant by checking for `subtype: "audio"`.
The same file could be uploaded as either an audio block, or as a VoiceBlock. The same data will be available either way, but they will be rendered differently in the UI.
Includes metadata about the duration of the audio file in seconds, where available.
Audio files that you upload with the TalkJS UI will include the duration as long as the sender's browser can preview the file. Audio files that you upload with the REST API or Session.uploadAudio will include the duration if you specified it when uploading. Audio files attached in a reply to an email notification will not include the duration. */
export interface AudioBlock  {
/** The duration of the audio in seconds, if known */
readonly duration?: number;
/** The name of the audio file, including file extension */
readonly filename: string;
/** An encoded identifier for this file. Use in SendFileBlock to send this file in another message. */
readonly fileToken: FileToken;
/** The size of the file in bytes */
readonly size: number;
readonly subtype: "audio";
readonly type: "file";
/** The URL where you can fetch the file */
readonly url: string;
}
  

## VoiceBlock
/** A FileBlock variant for a voice recording attachment, with additional voice-recording-specific metadata.
You can identify this variant by checking for `subtype: "voice"`.
The same file could be uploaded as either a voice block, or as an AudioBlock. The same data will be available either way, but they will be rendered differently in the UI.
Includes metadata about the duration of the recording in seconds, where available.
Voice recordings done in the TalkJS UI will always include the duration. Voice recordings that you upload with the REST API or Session.uploadVoice will include this metadata if you specified it when uploading.
Voice recordings will never be taken from a reply to an email notification. Any attached audio file will become an AudioBlock instead of a voice block. */
export interface VoiceBlock  {
/** The duration of the voice recording in seconds, if known */
readonly duration?: number;
/** The name of the file, including file extension */
readonly filename: string;
/** An encoded identifier for this file. Use in SendFileBlock to send this voice recording in another message. */
readonly fileToken: FileToken;
/** The size of the file in bytes */
readonly size: number;
readonly subtype: "voice";
readonly type: "file";
/** The URL where you can fetch the file */
readonly url: string;
}
</details>
</Callout>

## LocationBlock
/** A block showing a location in the world, typically because a user shared their location in the chat.
In the TalkJS UI, location blocks are rendered as a link to Google Maps, with the map pin showing at the specified coordinate. A thumbnail shows the surrounding area on the map. */
export interface LocationBlock  {
/** The north-south coordinate of the location.
Usually listed first in a pair of coordinates.
Must be a number between -90 and 90 */
readonly latitude: number;
/** The east-west coordinate of the location.
Usually listed second in a pair of coordinates.
Must be a number between -180 and 180 */
readonly longitude: number;
readonly type: "location";
}

## SendContentBlock
/** The version of ContentBlock that is used when sending or editing messages.
This is the same as ContentBlock except it uses SendFileBlock instead of FileBlock
`SendContentBlock` is a subset of `ContentBlock`. This means that you can re-send the `content` from an existing message without any issues:
```ts
const existingMessage: MessageSnapshot = ...;
const convRef = session.conversation('example_conversation_id');
convRef.send({ content: existingMessage.content });
``` */
export type SendContentBlock = TextBlock|SendFileBlock|LocationBlock;

## SendFileBlock
/** The version of FileBlock that is used when sending or editing messages.
When a user receives the message you send with `SendFileBlock`, this block will have turned into one of the FileBlock variants.
For information on how to obtain a file token, see FileToken.
The `SendFileBlock` interface is a subset of the `FileBlock` interface. If you have an existing `FileBlock` received in a message, you can re-use that block to re-send the same attachment:
```ts
const existingFileBlock = ...;
const imageToShare = existingFileBlock.content[0] as ImageBlock
const convRef = session.conversation('example_conversation_id');
convRef.send({ content: [imageToShare] });
``` */
export interface SendFileBlock  {
/** The encoded identifier for the file, obtained by uploading a file with Session.sendFile, or taken from another message. */
fileToken: FileToken;
type: "file";
}

## FileToken
/** A token representing a file uploaded to TalkJS.
You cannot create a FileToken yourself. Get a file token by uploading your file to TalkJS with Session.uploadFile, or one of the subtype-specific variants like Session.uploadImage. Alternatively, take a file token from an existing FileBlock to re-send an attachment you received, without having to download and re-upload the file. You can also upload files using the REST API. This system ensures that all files must be uploaded to TalkJS before being sent to users, limiting the risk of malware.
Passed in SendFileBlock when you send a message containing a file attachment.
We may change the FileToken format in the future. Do not store old file tokens for future use, as these may stop working.
Using a file input
```ts
// From `<input type="file">`
const file: File = fileInputElement.files[0];
const myFileToken = await session.uploadFile(file, { filename: file.name });
const block = {
type: 'file',
fileToken: myFileToken,
};
session.conversation('example_conversation_id').send({ content: [block] });
```
Re-sending a file from a previous message
```ts
session.conversation('example_conversation_id').send({
content: previousMessageSnapshot.content
});
``` */
export type FileToken = string & {
readonly __tag: Record<"TalkJS Encoded File Token", true>;
};