FeaturesRealtimeMessage History

Message History

Persist messages to the database and load them on demand. Useful for chat rooms, activity feeds, and any channel where new users need to see past messages.

Persist a message

Pass { persist: true } when publishing:

channel.publish('message', {
  userId: user.id,
  text: 'Hello, room!',
  timestamp: Date.now(),
}, { persist: true })

Messages are stored in your project’s D1 database under the realtime_messages table.

Load history

const history = await channel.getHistory(50)
// Returns up to 50 most recent messages, newest first

With a cursor (for pagination):

const firstPage = await channel.getHistory(50)
const oldest = firstPage[firstPage.length - 1]
 
const nextPage = await channel.getHistory(50, oldest.created_at)

History message shape

interface HistoryMessage {
  id: string
  room_id: string    // the channel topic
  user_id: string
  event: string      // the event name you published
  data: any          // the payload you published
  created_at: number // Unix timestamp (ms)
}

Group chat example with history

import { useAerostack } from '@aerostack/react'
import { useEffect, useState } from 'react'
 
function ChatRoom({ roomId, userId }) {
  const { realtime } = useAerostack()
  const [messages, setMessages] = useState([])
  const [channel, setChannel] = useState(null)
 
  useEffect(() => {
    const ch = realtime.channel(`chat/${roomId}`)
 
    // Load history first
    ch.getHistory(50).then(history => {
      const formatted = history.reverse().map(m => ({
        id: m.id,
        userId: m.user_id,
        text: m.data.text,
        timestamp: m.created_at,
      }))
      setMessages(formatted)
    })
 
    ch
      .on('message', ({ data }) => {
        setMessages(prev => [...prev, {
          id: Date.now().toString(),
          userId: data.userId,
          text: data.text,
          timestamp: Date.now(),
        }])
      })
      .subscribe()
 
    setChannel(ch)
    return () => ch.unsubscribe()
  }, [realtime, roomId])
 
  const sendMessage = (text) => {
    channel?.publish('message', { userId, text }, { persist: true })
    // Add optimistically
    setMessages(prev => [...prev, {
      id: Date.now().toString(),
      userId,
      text,
      timestamp: Date.now(),
    }])
  }
 
  return (
    <div>
      {messages.map(m => (
        <div key={m.id}>{m.userId}: {m.text}</div>
      ))}
      <button onClick={() => sendMessage('Hello!')}>Send</button>
    </div>
  )
}
⚠️

History is fetched via REST (not WebSocket). Make sure your API key is configured in AerostackProvider so the history request is authenticated.

See the Group Chat example for a complete multi-room implementation with history, presence, and participant lists.