The React integration is context-based. A provider higher in the tree creates the underlying ClientTransport (and, for the Vercel layer, the ChatTransport adapter) and exposes them through React context. Every hook in this section reads from the nearest provider.
There are two providers. Use TransportProvider from the generic entry point when you build a UI directly against AI Transport's hooks. Use ChatTransportProvider from the Vercel entry point when you wire AI Transport into Vercel's useChat. ChatTransportProvider internally wraps its children with a TransportProvider, so both layers' hooks resolve from a single provider.
1
2
import { TransportProvider } from '@ably/ai-transport/react';
import { ChatTransportProvider } from '@ably/ai-transport/vercel/react';TransportProvider
Creates a ClientTransport and makes it available to descendant components. Wraps children with Ably's ChannelProvider using the supplied channelName. Descendants read the transport with useClientTransport.
1
2
3
4
5
6
import { TransportProvider } from '@ably/ai-transport/react';
import { UIMessageCodec } from '@ably/ai-transport/vercel';
<TransportProvider channelName="conversation-42" codec={UIMessageCodec} api="/api/chat">
<Chat />
</TransportProvider>Parameters
The provider accepts every ClientTransportOptions field except channel (managed internally), plus a channelName.
channelNamerequiredStringcodecrequiredCodec<TEvent, TMessage>apirequiredStringclientIdoptionalStringheadersoptionalRecord<string, string> or () => Record<string, string>bodyoptionalRecord<string, unknown> or () => Record<string, unknown>credentialsoptionalRequestCredentialsfetchoptionaltypeof fetchmessagesoptionalTMessage[]loggeroptionalLoggerIf createClientTransport throws during construction, the error is surfaced through useClientTransport as transportError — the component tree does not crash and children are still rendered.
For multiple transports, nest providers with distinct channelName values. Descendants call useClientTransport({ channelName }) to disambiguate.
ChatTransportProvider
Creates a ChatTransport adapter for Vercel's useChat, alongside the underlying ClientTransport. Wraps children with a TransportProvider using UIMessageCodec, so the Ably channel lifecycle is managed in one place.
1
2
3
4
5
import { ChatTransportProvider } from '@ably/ai-transport/vercel/react';
<ChatTransportProvider channelName="conversation-42">
<Chat />
</ChatTransportProvider>Parameters
The provider accepts every VercelClientTransportOptions field (defaulting api to /api/chat), plus a channelName.
channelNamerequiredStringapioptionalString/api/chat.clientIdoptionalStringheadersoptionalRecord<string, string> or () => Record<string, string>bodyoptionalRecord<string, unknown> or () => Record<string, unknown>credentialsoptionalRequestCredentialsfetchoptionaltypeof fetchmessagesoptionalUIMessage[]loggeroptionalLoggerchatOptionsoptionalChatTransportOptionsChatTransportOptions for customising the adapter (for example, prepareSendMessagesRequest).ChatTransport itself is not closed on unmount. The underlying ClientTransport's lifecycle is managed by the wrapping TransportProvider. Multiple ChatTransportProviders can be nested using distinct channelName values; each merges its transport into the parent registry, so descendants can access multiple transports via useChatTransport({ channelName }).
Example
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
'use client';
import { useEffect, useState } from 'react';
import * as Ably from 'ably';
import { AblyProvider } from 'ably/react';
import { ChatTransportProvider } from '@ably/ai-transport/vercel/react';
import { Chat } from './chat';
function Providers({ children }) {
const [client, setClient] = useState(null);
useEffect(() => {
const ably = new Ably.Realtime({ authUrl: '/auth' });
setClient(ably);
return () => ably.close();
}, []);
if (!client) return null;
return <AblyProvider client={client}>{children}</AblyProvider>;
}
export default function Page() {
const chatId = 'conversation-42';
return (
<Providers>
<ChatTransportProvider channelName={chatId}>
<Chat chatId={chatId} />
</ChatTransportProvider>
</Providers>
);
}