Intégration avancée dans votre app
Mis à jour le 29 juillet 2026
Intégration avancée dans votre app
ChatKit ne se limite pas à un widget de chat isolé. Un assistant qui ignore qui lui parle et sur quelle page il est convoqué reste un gadget ; celui qui connaît l’utilisateur, sa page courante et l’état de son panier devient un raccourci vers votre produit. Dans cette leçon, vous apprendrez à intégrer profondément l’agent dans votre application : authentification, contexte applicatif, événements bidirectionnels, et modes d’affichage avancés.
Authentification et sessions
En production, chaque utilisateur a sa propre session avec l’agent. Deux prop du ChatProvider s’en chargent : headers transporte le jeton d’authentification, et metadata accompagne chaque requête d’informations métier — identifiant, offre souscrite, langue. La distinction compte : le jeton sert à prouver l’identité, les métadonnées à personnaliser la réponse. Ne mettez jamais dans les secondes ce qui doit être vérifié.
import { ChatProvider, ChatWindow, MessageInput } from "@openai/chatkit/react";
function ChatAuthentifie({ user }) {
return (
<ChatProvider
endpoint="/api/chat"
headers={{
Authorization: `Bearer ${user.token}`,
}}
metadata={{
userId: user.id,
plan: user.plan,
langue: "fr",
}}
>
<ChatWindow />
<MessageInput />
</ChatProvider>
);
}
Côté backend, la dépendance FastAPI lit l’en-tête, valide le jeton et reconstruit l’utilisateur à partir de vos propres sources. C’est cet objet-là, et non les métadonnées reçues du navigateur, qui alimente le contexte du Runner et les instructions de l’agent.
from fastapi import FastAPI, Request, Depends
from agents import Agent, Runner
app = FastAPI()
async def get_current_user(request: Request):
token = request.headers.get("Authorization", "").replace("Bearer ", "")
# Vérifier le token et récupérer l'utilisateur
return {"id": "usr_123", "nom": "Marie Dupont", "plan": "Pro"}
@app.post("/api/chat")
async def chat(request: Request, user=Depends(get_current_user)):
body = await request.json()
contexte = SessionUtilisateur(
user_id=user["id"],
nom=user["nom"],
plan=user["plan"],
)
agent = Agent(
name="Assistant",
instructions=f"Vous assistez {user['nom']} (plan {user['plan']}).",
model="gpt-5.6-terra",
)
result = await Runner.run(agent, body["message"], context=contexte)
return {"response": result.final_output}
L’offre injectée dans les instructions change immédiatement le comportement : sur un plan Pro, l’agent propose l’export avancé ; sur un plan gratuit, il oriente vers la mise à niveau au lieu de décrire une fonctionnalité inaccessible.
Injecter le contexte applicatif
Votre agent peut aussi accéder au contexte de la page où se trouve l’utilisateur. Un visiteur qui ouvre le chat depuis une fiche produit veut presque toujours parler de ce produit ; le lui faire décrire est une perte de temps que vous lui infligez. En capturant l’URL et quelques attributs de données du DOM, vous transmettez cette situation à l’agent et adaptez jusqu’au texte du champ de saisie.
import { useEffect, useState } from "react";
import { ChatProvider, ChatWindow, MessageInput } from "@openai/chatkit/react";
function ChatContextuel() {
const [pageContext, setPageContext] = useState({});
useEffect(() => {
// Capturer le contexte de la page courante
setPageContext({
page: window.location.pathname,
produitConsulte: document.querySelector("[data-product-id]")?.dataset.productId,
categorieActive: document.querySelector("[data-category]")?.dataset.category,
});
}, []);
return (
<ChatProvider
endpoint="/api/chat"
metadata={{ context: pageContext }}
>
<ChatWindow />
<MessageInput
placeholder={
pageContext.produitConsulte
? "Une question sur ce produit ?"
: "Comment puis-je vous aider ?"
}
/>
</ChatProvider>
);
}
Le useEffect s’exécute au montage : sur une application à navigation côté client, pensez à le réexécuter au changement de route, faute de quoi l’agent restera persuadé que l’utilisateur consulte encore la première page ouverte.
Événements bidirectionnels
L’intégration devient réellement profonde lorsque le chat et l’application se parlent dans les deux sens. Une référence sur le provider permet à votre code d’envoyer un message à la place de l’utilisateur — c’est ainsi qu’un bouton « Besoin d’aide ? » placé n’importe où dans l’interface ouvre une conversation déjà cadrée. Dans l’autre sens, onEvent vous expose ce qui se passe dans le chat : un appel de tool naviguer_vers déclenche une redirection, une action ouvrir_panier fait glisser votre panneau latéral. L’agent cesse alors de décrire l’interface et se met à la piloter.
import { useRef } from "react";
import { ChatProvider, ChatWindow, MessageInput } from "@openai/chatkit/react";
function ChatInteractif() {
const chatRef = useRef(null);
// Envoyer un message programmatiquement
const envoyerMessage = (message) => {
chatRef.current?.sendMessage(message);
};
// Écouter les événements du chat
const handleEvent = (event) => {
if (event.type === "tool_call" && event.tool === "naviguer_vers") {
// L'agent demande de naviguer vers une page
window.location.href = event.args.url;
}
if (event.type === "action" && event.action === "ouvrir_panier") {
// Ouvrir le panneau panier
document.dispatchEvent(new CustomEvent("ouvrir-panier"));
}
};
return (
<ChatProvider endpoint="/api/chat" onEvent={handleEvent} ref={chatRef}>
{/* Bouton externe qui déclenche le chat */}
<button onClick={() => envoyerMessage("Aide-moi à choisir un produit")}>
Besoin d'aide ?
</button>
<ChatWindow />
<MessageInput />
</ChatProvider>
);
}
Une navigation déclenchée par un modèle mérite la même prudence qu’une saisie utilisateur : restreignez les destinations acceptées à vos propres routes plutôt que de suivre aveuglément l’URL reçue.
Mode panneau latéral
Reste la question de l’emplacement. Le plein écran convient à un produit dont le chat est l’interface ; pour tout le reste, le panneau latéral rétractable s’impose, parce qu’il laisse l’utilisateur voir la page dont il parle pendant qu’il pose sa question. Un bouton flottant en bas à droite ouvre et ferme le panneau, dont la position hors écran (right: -400px) et la transition donnent l’effet de glissement.
import { useState } from "react";
import { ChatProvider, ChatWindow, MessageInput } from "@openai/chatkit/react";
function ChatPanneauLateral() {
const [ouvert, setOuvert] = useState(false);
return (
<>
{/* Bouton flottant */}
<button
onClick={() => setOuvert(!ouvert)}
style={{
position: "fixed",
bottom: "24px",
right: "24px",
width: "56px",
height: "56px",
borderRadius: "50%",
background: "#2563EB",
color: "white",
border: "none",
cursor: "pointer",
fontSize: "24px",
zIndex: 1000,
boxShadow: "0 4px 12px rgba(0,0,0,0.3)",
}}
>
{ouvert ? "×" : "?"}
</button>
{/* Panneau latéral */}
<div style={{
position: "fixed",
top: 0,
right: ouvert ? 0 : "-400px",
width: "400px",
height: "100vh",
background: "#0F172A",
transition: "right 0.3s ease",
zIndex: 999,
display: "flex",
flexDirection: "column",
boxShadow: ouvert ? "-4px 0 24px rgba(0,0,0,0.3)" : "none",
}}>
<div style={{ padding: "16px", borderBottom: "1px solid #1E293B" }}>
<h3 style={{ margin: 0, color: "#F8FAFC" }}>Assistant</h3>
</div>
<ChatProvider endpoint="/api/chat">
<ChatWindow style={{ flex: 1 }} />
<MessageInput />
</ChatProvider>
</div>
</>
);
}
Les 400 pixels fixes conviennent à un écran d’ordinateur ; sur mobile, passez le panneau en pleine largeur, sans quoi il masquera la page tout en restant trop étroit pour être confortable.
Persistance des conversations
Enfin, une conversation qui disparaît au rechargement de la page trahit la promesse d’un assistant. En fournissant un conversationId et deux fonctions de chargement et de sauvegarde, vous branchez ChatKit sur votre propre stockage : l’utilisateur qui revient le lendemain retrouve le fil où il l’avait laissé, et vos équipes support disposent d’un historique consultable.
function ChatPersistant({ userId }) {
return (
<ChatProvider
endpoint="/api/chat"
conversationId={`conv_${userId}_latest`}
onConversationLoad={async (convId) => {
// Charger l'historique depuis votre API
const response = await fetch(`/api/conversations/${convId}`);
return response.json();
}}
onConversationSave={async (convId, messages) => {
// Sauvegarder l'historique
await fetch(`/api/conversations/${convId}`, {
method: "PUT",
body: JSON.stringify({ messages }),
});
}}
>
<ChatWindow />
<MessageInput />
</ChatProvider>
);
}
Points clés à retenir
- Passez le token d’authentification via
headersdans leChatProvider - Le contexte applicatif (page, produit consulté) enrichit les réponses de l’agent
- Les événements bidirectionnels synchronisent le chat avec votre application
- Le mode panneau latéral est le pattern d’intégration le plus courant
- La persistance des conversations permet de reprendre où l’utilisateur s’est arrêté