livqenoDocs

ChatMessage History

Message History

Load older messages, one page at a time, newest first.

Message history is every message saved in a conversation. Live events only show messages that arrive while you're connected, so you load history to show what came before: when the chat screen opens, and when the user scrolls up ("Load earlier").

Where this fits: your app is connected to a conversation (see the Chat quickstart). Load the latest page of history, then keep it up to date with live message events from Messages.

A typical chat screen

  1. The user opens the chat. Load the newest page (say, 50 messages).
  2. Show them, and start listening for live message events.
  3. The user scrolls to the top. Load the next older page with the cursor you got in step 1.
  4. Repeat until hasMore is false.

Load a page

In your app:

const page = await chat.messages.list({ room: 'conv_9WcQ…', limit: 50 });
// { data: [...], nextCursor: '...', previousCursor: '...', hasMore: true }
 
const older = await chat.messages.list({ before: page.nextCursor });
const newer = await chat.messages.list({ after: page.previousCursor });

How it works:

  • Messages come newest first. Reverse them if your UI shows the oldest at the top.
  • A cursor is a bookmark into the history. Use nextCursor to get older messages, and previousCursor for newer ones.
  • Pass a cursor back exactly as you got it. Don't try to read or build one.
  • hasMore: false means you've reached the start of the conversation.

Why there's no offset

There's no "skip 100 messages" option, on purpose:

  • A large offset is slow.
  • In a live chat, new messages shift the offset. If 3 messages arrive while you load page 2, you'd see 3 messages twice.
  • A cursor points to an exact spot, so it stays correct no matter what arrives.

After a reconnect

You don't need history to fill gaps after a dropped connection. The SDK catches up on its own and delivers missed messages as normal message events, then fires recovered. See Chat Events. You only load history yourself if you use the raw WebSocket protocol.

Filters

FilterWhat it doesUse it for
threadRootIdOnly messages in one thread.A thread side panel. See Threads.
senderIdOnly messages from one user."Messages from this customer".
includeDeletedInclude deleted messages.Moderation review.

From your backend

Your backend can read history too, for example to export a support transcript or review reports. It uses the API key instead of a chat token, so it can read any conversation in the environment:

import { Livqeno } from '@livqeno/server';
const livqeno = new Livqeno({
  apiKey: process.env.LIVQENO_API_KEY,
  baseUrl: process.env.LIVQENO_API_URL, // https://api.livqeno.com
});
 
const page = await livqeno.chat.listMessages('support-room-42', { limit: 50 });

Cursors work the same way on the backend and in the app.

Common errors

ProblemCauseFix
Messages appear in reverse orderHistory is newest first.Reverse the page before rendering, or use React's useMessages(), which is oldest first.
The same message shows twice after "Load earlier"You added a live message that was also in a history page.Use the message id as the key, and skip ids you already have.
ROOM_NOT_FOUNDThe user isn't a member, or the token doesn't include this conversation.See Members.

Next steps