Transporte: WebSocket, fallback HTTP e reconexão
Como o widget se comunica com o servidor do chat: endereços, subprotocolo rc.v1, formato dos quadros, códigos de erro e fechamento, limites, reconexão com seq e deduplicação e fallback HTTP por Server-Sent Events e long polling.
Esta página descreve o que acontece entre o widget no navegador e o servidor do chat. Ela serve para solucionar problemas (aba de rede das ferramentas do desenvolvedor), definir regras de proxy e firewall e configurar sua Content Security Policy.
Importante: o protocolo de comunicação é a interface entre nosso widget e nosso servidor. Clientes próprios que usam o protocolo diretamente não têm suporte oficial; campos podem ser ampliados dentro da versão 1 do protocolo. Para interfaces próprias, use a API JavaScript; para conexões de servidor, webhooks e a API do servidor.
Endereços
- WebSocket:
wss://ws.reactive.chat/rc_wss/ - Fallback HTTP, formulário offline, uploads: o mesmo endereço com
https://, ou seja,https://ws.reactive.chat/rc_wss/h/…,https://ws.reactive.chat/api/offline/<SITE_KEY>ehttps://ws.reactive.chat/rc_wss/upload/… - Arquivos do widget:
https://cdn.reactive.chat/
Como o widget encontra o endereço WebSocket:
data-rc-ws-urlna tag do carregador,window.ReactiveChatSettings.wsUrlouReactiveChat('boot', { wsUrl })– se definido, esse valor se aplica.- Caso contrário, é deduzido do local de
loader.js:wss://ws.+ as últimas duas partes do domínio +/rc_wss/.cdn.reactive.chatvirawss://ws.reactive.chat/rc_wss/.
Disso surgem duas armadilhas:
- Se você hospedar
loader.jsno seu domínio, o widget deduz um endereço sob seu domínio. Nesse caso, definadata-rc-ws-url(veja Início rápido). - Com terminações em duas partes, como
.co.uk, a dedução falha. Definadata-rc-ws-urlexplicitamente.
A rota WebSocket não avalia parâmetros de query.
Estabelecer a conexão
- Momento: o widget não se conecta durante o carregamento da página, mas na primeira interação real (movimento do mouse, clique, tecla, roda do mouse, toque, foco). Conecta imediatamente se a janela do chat estiver aberta ou sendo aberta, houver uma conversa conhecida do visitante ou mensagens não enviadas em espera. Com
data-rc-connect="load"em qualquer elemento (normalmente a tag do carregador) ouwindow.ReactiveChatSettings.connect = 'load', conecta no carregamento como antes. Regras acionadas após um tempo desde a visualização da página contam a partir da primeira interação. - Subprotocolo: o widget abre
new WebSocket(url, 'rc.v1'), e o servidor retornarc.v1. A versão do protocolo não está no endereço, mas em cada quadro (v: 1). - Somente quadros de texto, em UTF-8; um quadro = uma mensagem. Sem compressão (
permessage-deflateestá desativado no servidor). - Handshake: após
open, o widget enviainitem no máximo 5 segundos; o servidor responde cominit_ok. Seopennão chegar em 8 segundos, a tentativa conta como malsucedida; seinit_oknão chegar em 10 segundos, o widget se reconecta. - Verificação de origem: o servidor compara o nome do host do cabeçalho
Origincom os domínios do projeto (Origens permitidas na conta). Esquema e porta não contam; subdomínios correspondem (www.your-company.comcorresponde ayour-company.com,notyour-company.comnão). Na falha: erroorigin_denied, depois fechamento 1008, sem nova tentativa. Se nenhum domínio estiver cadastrado no projeto, não há verificação de origem; portanto, cadastre sempre seus domínios.
Formato dos quadros
Toda mensagem nas duas direções tem este formato:
{ "v": 1, "t": "msg", "id": "01JAB3C4D5E6F7G8H9JKMNPQRS", "ts": 1792500000000, "d": { } }
- v (inteiro, obrigatório) – versão do protocolo, atualmente
1. - t (string, obrigatório) – tipo de mensagem,
[a-z0-9_]{1,24}. - id (string, obrigatório) – ULID: 26 caracteres de Crockford Base32, somente maiúsculas. Também é a chave de deduplicação.
- ts (inteiro, obrigatório) – milissegundos desde 1970, apenas para diagnóstico.
- d (objeto, obrigatório) – dados, nunca
null,{}quando vazio.
Tipos e campos desconhecidos são ignorados sem aviso; isso mantém widgets antigos compatíveis com servidores mais novos.
Tipos de mensagem em resumo
Do widget para o servidor:
- init – registro da conexão: chave do site, sessão, visitante, aba e ID da conversa, idioma, estado do consentimento, identidade assinada, se houver (
user), contexto da página (ctx) e ponto de retomada (resume). - msg – mensagem do visitante (texto, até 5 anexos, resposta a respostas rápidas ou formulários).
- typing – indicador de digitação (
start/stop). O conteúdo do campo de entrada nunca é transmitido. - read – lido até
seq. - ctx – mudança de contexto, por exemplo, na navegação em uma SPA ou após
identify. - csat – avaliação (polegar para cima/baixo, comentário de até 1.000 caracteres).
- upload_req – solicitação de autorização de upload (nome, tipo MIME, tamanho, SHA-256).
- transcript, forget, consent – conversa por e-mail, excluir os próprios dados, conceder/revogar consentimento.
- ping – manutenção da conexão.
Do servidor para o widget:
- init_ok – IDs confirmados, histórico, design, recursos e limites (veja abaixo), resultado da verificação de identidade (
identity.verified). - msg – mensagens (incluindo o eco da mensagem do próprio visitante com
client_id). - bot_typing, bot_stream – o assistente de IA está pensando ou escrevendo;
bot_streamsempre transmite o texto inteiro visível até então, no máximo a cada 150 ms. - typing, read, handoff, queue_pos, proactive, conv_list, error, pong.
Códigos de erro
Um erro chega como quadro t: "error" com d.code, d.message (inglês, apenas para desenvolvedores), d.retry (no, immediate, backoff, after_reinit) e, quando necessário, d.retry_after_ms e d.detail. A lista é fechada; um código desconhecido é tratado como internal.
- bad_json – JSON inválido; após três ocorrências, fechamento 1008.
- bad_envelope – o quadro viola o formato (também: ULID com diferença superior a 24 h,
detail.reason: stale_or_future). - unsupported_version – não é possível negociar a versão; fechamento 4001.
- unknown_site_key – chave do site desconhecida, projeto pausado ou arquivado; fechamento 4002.
- origin_denied – origem fora dos domínios do projeto; fechamento 1008.
- visitor_blocked – visitante bloqueado; fechamento 1008.
- auth_failed – verificação de identidade falhou,
detail.reason:no_hash,bad_hash,bad_exp,expired,exp_too_far. A sessão continua anônima. - not_initialized / already_initialized – mensagem antes de
initou um segundoinit. - init_timeout – nenhum
initem 5 s; fechamento 4004. - conversation_not_found / conversation_closed
- rate_limited – limite de requisições; com
retry_after_ms. Se ocorrer repetidamente na mesma conexão, o servidor fecha com 4008. - payload_too_large – quadro acima de 64 KiB.
- msg_too_long – texto maior que o limite do plano,
detail.max. - unsupported_kind, attachment_invalid
- upload_disabled, upload_too_large, upload_mime_denied, upload_expired
- consent_required – a ação exige consentimento.
- dnd_active – “Não perturbe” está ativo.
- session_conflict – conexões demais na mesma sessão (mais de 3); fechamento 4003, a aba passa a seguir outra.
- internal, unavailable – temporário; tentar novamente após uma espera.
Códigos de fechamento
- 1000, 1001, 1006, 1011, 1013, 4004 – o widget se reconecta (após uma espera).
- 1008 – origem rejeitada, JSON repetidamente inválido, bloqueio pela proteção contra abuso. Sem nova tentativa nesta página.
- 4001 – não é possível negociar a versão. Sem nova tentativa.
- 4002 – chave do site desconhecida ou projeto inativo. Sem nova tentativa.
- 4008 – limite atingido repetidamente. O widget aguarda
retry_after_mse se reconecta. - 4003 – conflito de sessão; a aba segue outra aba.
Limites por conexão
O servidor envia os valores vinculantes em init_ok.limits e init_ok.features:
- heartbeat_ms 25.000 – o widget envia um
ping25 s após a última mensagem de saída. - pong_timeout_ms 10.000 – dois
pongs ausentes causam uma reconexão. - idle_timeout_ms 70.000 – o servidor fecha após 70 s sem receber um quadro (1001).
- max_frame_bytes 65.536 – quadros maiores:
payload_too_large. - msg_per_10s 20 e frames_per_10s 120 – token bucket por conexão; acima disso,
rate_limited. - reconnect_cap_ms 30.000 – maior espera entre tentativas.
- dedup_window_ms 86.400.000 – 24 horas de deduplicação.
- features.max_msg_len – caracteres (pontos de código Unicode) por mensagem do visitante: 1.000 no plano Free, 4.000 nos planos pagos. O widget não envia textos longos demais.
- features.max_upload_bytes, features.allowed_mime – veja Limites e cotas.
Reconexão, ordem e duplicatas
- Espera:
min(30000, 500 × 2^(attempt−1))ms, usando um valor aleatório na metade superior (tentativa 1: 250–500 ms; a partir da 7: 15–30 s). Três vezes maior em abas em segundo plano. Umretry_after_msdo servidor é o limite inferior. O número de tentativas é ilimitado; o contador só é zerado eminit_ok. Se o navegador informaronline, o widget tenta imediatamente; se estiver offline, espera. - Ordem: cada mensagem de uma conversa tem um
seqsem lacunas a partir de 1. As mensagens são exibidas porseq, não por horário. Na reconexão, o widget enviaresume.last_seqe até 50 IDs pendentes; o servidor entrega tudo depois desse ponto (no máximo 100 mensagens; caso contrário,has_more) e repete as confirmações das mensagens já recebidas. - Sem duplicatas: o servidor lembra cada
idde mensagem por 24 horas. Uma mensagem repetida não é armazenada de novo, mas recebe a mesma confirmação. “Enviar de novo” no widget usa o mesmoid. - Estados de uma mensagem de saída:
pending→sent→delivered(eco do servidor) →read;failedapós 5 tentativas, após 24 h ou comretry: "no". - Buffer offline: se a conexão cair, as mensagens entram em um buffer (no máximo 50 entradas, 128 KiB, 24 h), com consentimento em
localStorage, sem ele emsessionStorage, e são enviadas no próximoinit_ok. - Várias abas, uma conexão: as abas de um site elegem uma líder (Web Locks; caso contrário, manutenção da conexão em
localStorage); só a líder mantém a conexão, e as outras se comunicam porBroadcastChannel.
Fallback HTTP
Se uma rede não permitir WebSocket, o chat continua por requisições HTTPS comuns, com os mesmos quadros e limites. Somente o widget usa isso; a interface dos atendentes sempre conecta por WebSocket. A versão resumida para editores está em Fallback HTTP.
Quando se aplica:
- o navegador não oferece suporte a WebSocket;
- duas tentativas de WebSocket falham seguidas antes de qualquer WebSocket ter sido estabelecido nesta página (uma tentativa sem resultado após 8 segundos conta como malsucedida);
sessionStoragecontém uma entradarc_httpcom menos de 30 minutos (páginas seguintes na mesma aba);- você força com
data-rc-transport="http"(em qualquer elemento presente no documento na inicialização) ou comwindow.ReactiveChatSettings = { transport: 'http' }antes do carregador.ReactiveChat('boot', { transport: 'http' })não tem efeito: o tipo de conexão é fixado na inicialização.
Sem fetch no navegador, não há fallback. Se uma conexão WebSocket existente cair, o widget se reconecta por WebSocket. Após um fallback, verifica silenciosamente uma vez por página se um WebSocket já passa; se passar, exclui rc_http, e a próxima página volta a usar WebSocket.
As requisições (em https://ws.reactive.chat/rc_wss/h/):
- POST h/auf – abre a conexão. Resposta
{"v":1,"cid":"…","tok":"…","poll_ms":25000,"idle_ms":60000}.toké um token de conexão de curta duração (32 caracteres). - GET h/<cid>/sse?tok=… – Server-Sent Events,
id:edata:por quadro, manutenção da conexão a cada 15 s. Quadros perdidos são entregues porLast-Event-ID. - GET h/<cid>/poll?tok=…&nach=<n> – long polling; o servidor mantém a requisição aberta por até 25 s e responde com
{"v":1,"n":…,"rahmen":[…]}. - POST h/<cid>/tx?tok=… – enviar,
text/plain, um quadro ou um array de no máximo 20 quadros; resposta 204. - POST h/<cid>/zu?tok=… – fechar (por
sendBeacon).
O widget tenta SSE primeiro; se nenhum primeiro quadro chegar em 5 segundos (por exemplo, por buffering em um proxy), muda para long polling. Trata erros como 404 (unbekannt), 403, 413 ou 429 como queda da conexão e tenta novamente após uma espera. Após 60 segundos sem requisição, o servidor fecha a conexão. CORS: Access-Control-Allow-Origin reflete a origem, sem credenciais; a verificação de origem acontece em init, como no WebSocket.
Requisitos do seu lado:
connect-srcda CSP contém o endereço do chat comwss://ehttps://.- Firewalls e proxies permitem requisições de pelo menos 30 segundos.
- Seu proxy próprio repassa
/rc_wss/sem buffering (nginxproxy_buffering offeproxy_cache off, Apacheflushpackets=on, Caddyflush_interval -1) e não registra/rc_wss/h/no log de acesso (token na query). Veja Domínio próprio.
Armazenado no navegador: apenas a entrada rc_http em sessionStorage com o horário da conexão HTTPS, sem dados pessoais.
Qual rota está ativa
Na aba de rede das ferramentas do desenvolvedor:
- WebSocket: uma conexão do tipo WebSocket com
wss://ws.reactive.chat/rc_wss/(ou seu subdomínio). Nos quadros, você vêinit,init_ok,ping/ponge as mensagens. - Fallback HTTP: primeiro
h/auf, depois um…/sseprolongado (ou…/pollrecorrente) e um…/txpara cada mensagem enviada.
A seguir: Limites e cotas · Solução de problemas
Последна актуализация: